UNITY版本2022.3.11f1 3D URP 项目
我正在开发一个简单的玩家控制器脚本,但我很难确定为什么速度会以意想不到的方式运行。
两个问题:
1 - 当我在向前移动时旋转玩家刚体时 - 速度/方向捕捉到世界的 x 轴。
黄线是速度 红线是作用力(基于键(W)输入和鼠标输入方向的推动)
视频演示:https://clipchamp.com/watch/kpePTVpR73s
问题 - 为什么速度会像这样捕捉到世界轴以及我该如何开始解决?
2 - 当我按空格键在 y 方向施加脉冲力时,会在 z 世界轴方向施加一个力,该力正在推动刚体,我花了很多时间注释其他作用力并查看通过 UI 查找可能正在执行的操作。
再次
黄线是速度 红线是作用力(基于键(W)输入和鼠标输入方向的推动)
视频演示:https://clipchamp.com/watch/phAYs1v4ULU
问题 - 当脉冲设置为世界 y 时,为什么速度会立即与 z 方向成一定角度?为什么在圆弧路径的末端会出现偏转,就好像刚体碰撞到看不见的墙壁一样?
资产结构
相机 父级 - CameraHolder - MoveCamera 脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCamera : MonoBehaviour
{
public Transform cameraPosition;
// Update is called once per frame
void Update()
{
transform.position = cameraPosition.position;
}
}
Child - PlayerCam(主摄像头) - PlayerCam 脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCam : MonoBehaviour
{
public float sensX;
public float sensY;
public Transform orientation;
float xRotation;
float yRotation;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
// Get Mouse Input
float mouseX = Input.GetAxisRaw("Mouse X") * Time.deltaTime * sensX;
float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * sensY;
yRotation += mouseX;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
orientation.rotation = Quaternion.Euler(0, yRotation, 0);
}
}
玩家 父级 - 玩家 - 刚体 - 玩家运动脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[Header("Movement")]
public float moveSpeed;
float horizontalInput;
float verticalInput;
Vector3 moveDirection;
Rigidbody rb;
public float groundDrag;
public float jumpForce;
public float jumpCooldown;
public float airMultiplier;
bool readyToJump = true;
[Header("Keybinds")]
public KeyCode jumpKey = KeyCode.Space;
[Header("Ground Check")]
public float playerHeight;
public LayerMask whatIsGround;
public Transform orientation;
bool grounded;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
}
// Update is called once per frame
void Update()
{
Debug.DrawRay(rb.position, rb.velocity, Color.yellow);
Debug.DrawRay(rb.position, rb.GetAccumulatedForce(), Color.red);
// Ground Check
grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
MyInput();
SpeedControl();
// Handle drag
if (grounded)
rb.drag = groundDrag;
else
rb.drag = 0;
}
private void FixedUpdate()
{
MovePlayer();
}
private void MyInput()
{
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
if (Input.GetKey(jumpKey) && readyToJump && grounded)
{
readyToJump = false;
Jump();
Invoke(nameof(ResetJump), jumpCooldown);
}
}
private void MovePlayer()
{
// Calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
Debug.Log("Orientation --- " + orientation.position);
Debug.Log("Orientation --- " + orientation.forward);
Debug.DrawLine(rb.position, moveDirection, Color.green);
// On Ground
if (grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
else if (!grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
}
private void SpeedControl()
{
Vector3 flatVelocity = new Vector3(rb.velocity.x, 0f, rb.velocity.y);
// Limit velocity if needed
if(flatVelocity.magnitude > moveSpeed)
{
Vector3 limitedVelocity = flatVelocity.normalized * moveSpeed;
rb.velocity = new Vector3(limitedVelocity.x, rb.velocity.y, limitedVelocity.z);
}
}
private void Jump()
{
// Reset Y Velocity
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
}
private void ResetJump()
{
readyToJump = true;
}
}
儿童 - PlayerObj - 胶囊碰撞器
儿童 - 方向 - 只需变换方向
Child - CameraPos - 只需变换位置
我尝试了各种代码注释、日志记录和 UI 配置,以尝试并推理力如何作用在刚体上。
我在你的
SpeedControl()
方法中看到你有Vector3 flatVelocity = new Vector3(rb.velocity.x, 0f, rb.velocity.y);
。
这显然会将 RigidBody 的
Y
组件映射到其 Z
组件。
这可以解释捕捉的原因,因为 Y
看起来大多数时候都是零。因此,当您达到速度限制时,您将 Z
分量设置为 0,这将使其沿 X
轴捕捉。
这也可以解释跳跃问题,因为在这种情况下,
Y
速度不会为0,这意味着映射的Y
速度将映射到Z
轴,在跳跃时推动角色向前。
我想你想说的是:
Vector3 flatVelocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);