Unity中Rigidbody.MovePosition()行为异常问题排查
第三人称移动异常问题解决方案
问题现象
将以下代码挂载到勾选「Is Kinematic」选项的Rigidbody组件角色上时,出现角色长时间无移动响应,之后随机向前跳跃一段距离,再次按下W键重复该现象。此前使用transform.Translate可正常移动,但存在角色穿透地面问题。
原代码:
using UnityEngine; public class ThirdPersonMovement : MonoBehaviour { Rigidbody rb; private Animator animator; public float speed = 5f; void Start() { animator = GetComponent<Animator>(); rb = GetComponent<Rigidbody>(); } // Update is called once per frame void Update() { //Get player input based on world space. float playerHorizontalInput = Input.GetAxisRaw("Horizontal"); float playerVerticalInput = Input.GetAxisRaw("Vertical"); //Get camera-normalized directional vectors Vector3 forward = Camera.main.transform.forward; Vector3 right = Camera.main.transform.right; //Create direction-relative input vectors Vector3 forwardRelativeVerticalInput = playerVerticalInput * forward; Vector3 rightRelativeHorizontalInput = playerHorizontalInput * right; Vector3 cameraRelativeMovement = forwardRelativeVerticalInput + rightRelativeHorizontalInput; Vector3 movement = cameraRelativeMovement * speed * Time.deltaTime; rb.MovePosition(transform.position + movement); transform.forward = cameraRelativeMovement; if (cameraRelativeMovement != Vector3.zero) { animator.SetBool("IsMoving", true); } else { animator.SetBool("IsMoving", false); } } }
解决方案
1. 切换物理更新时机
Rigidbody相关操作必须放在FixedUpdate中执行,Update的帧间隔不稳定,会导致物理计算和输入不同步,引发延迟、跳跃等异常。
2. 清除相机向量的Y轴分量
相机的forward和right向量默认包含Y轴信息,会导致角色移动时出现上下偏移,需将Y轴置0并归一化,保证移动仅在水平平面进行。
3. 优化移动状态判断
直接通过输入的平方和判断是否有移动输入,避免Vector3.zero精确比较带来的误差(浮点运算存在精度问题)。
修改后的代码:
using UnityEngine; public class ThirdPersonMovement : MonoBehaviour { Rigidbody rb; private Animator animator; public float speed = 5f; void Start() { animator = GetComponent<Animator>(); rb = GetComponent<Rigidbody>(); } // 物理更新函数,固定时间步执行 void FixedUpdate() { float playerHorizontalInput = Input.GetAxisRaw("Horizontal"); float playerVerticalInput = Input.GetAxisRaw("Vertical"); // 提取相机水平方向向量,清除Y轴分量并归一化 Vector3 cameraForward = new Vector3(Camera.main.transform.forward.x, 0f, Camera.main.transform.forward.z).normalized; Vector3 cameraRight = new Vector3(Camera.main.transform.right.x, 0f, Camera.main.transform.right.z).normalized; // 计算相机相对的移动方向 Vector3 cameraRelativeMovement = cameraForward * playerVerticalInput + cameraRight * playerHorizontalInput; // 仅当有输入时才更新朝向 if (cameraRelativeMovement.magnitude > 0.1f) { transform.forward = cameraRelativeMovement.normalized; animator.SetBool("IsMoving", true); } else { animator.SetBool("IsMoving", false); } // 计算移动位移并应用到刚体 Vector3 movement = cameraRelativeMovement.normalized * speed * Time.fixedDeltaTime; rb.MovePosition(rb.position + movement); } }
额外说明
- 保持Rigidbody的「Is Kinematic」勾选,此模式下刚体不会受物理力影响,适合通过代码控制移动,同时能触发碰撞检测,避免穿透地面问题。
- 使用
Time.fixedDeltaTime替代Time.deltaTime,因为FixedUpdate的执行间隔是固定的,对应物理时间步。
内容的提问来源于stack exchange,提问作者hiling99
相关产品推荐
相关产品推荐

