使用Rigidbody.MovePosition/MoveRotation时角色停止后小幅旋转问题排查
问题
使用Rigidbody的MovePosition和MoveRotation实现角色平滑移动与旋转,需求为通过WSAD键控制角色旋转并沿当前方向前进。移动过程正常,但停止输入后角色有时会出现10-20度的小幅旋转,请问是代码问题还是其他原因?该如何修复?
原代码
Rigidbody rb; private float h_Input; private float v_Input; private Vector3 direction; public float moveSpeed = 8; public float rotateSpeed = 20; void Start() { rb = GetComponent<Rigidbody>(); } void Update() { } private void FixedUpdate() { Move(); } private void Move() { h_Input = Input.GetAxisRaw("Horizontal"); v_Input = Input.GetAxisRaw("Vertical"); if (h_Input!=0|| v_Input !=0) { direction = new Vector3(h_Input, 0, v_Input); Quaternion rotationTarget = Quaternion.LookRotation(direction, Vector3.up ); rb.MoveRotation(Quaternion.Lerp(rb.rotation,rotationTarget, rotateSpeed * Time.fixedDeltaTime)); rb.MovePosition(rb.position + transform.TransformDirection(Vector3.forward) * moveSpeed * Time.fixedDeltaTime); } }
原因分析
这是代码逻辑+物理引擎微小干扰共同导致的问题:
- 输入停止时,代码终止了旋转更新,但此时角色旋转可能还没完全插值到目标角度,后续没有逻辑维持旋转状态;
Quaternion.Lerp的特性是越接近目标插值速度越慢,可能导致最后几次输入中断时,目标旋转未完成;- 刚体默认的角阻力可能不足,停止输入后残留的微小角速度会引发旋转偏移。
修复方案
修改点说明
- 输入中断时主动锁定旋转、清除角速度,避免物理层面的偏移;
- 用
Quaternion.RotateTowards替代Lerp,以固定步长旋转,确保能精准到达目标角度; - 归一化输入方向,避免斜向输入时方向向量长度异常;
- 增大刚体角阻力,减少物理干扰。
修改后的代码
Rigidbody rb; private float h_Input; private float v_Input; private Vector3 direction; public float moveSpeed = 8; public float rotateSpeed = 20; void Start() { rb = GetComponent<Rigidbody>(); // 增大角阻力,防止残留角速度引发旋转 rb.angularDrag = 10f; } void Update() { } private void FixedUpdate() { Move(); } private void Move() { h_Input = Input.GetAxisRaw("Horizontal"); v_Input = Input.GetAxisRaw("Vertical"); if (h_Input != 0 || v_Input != 0) { // 归一化方向,避免斜向输入时向量长度异常 direction = new Vector3(h_Input, 0, v_Input).normalized; Quaternion rotationTarget = Quaternion.LookRotation(direction, Vector3.up); // 用RotateTowards实现固定步长旋转,替代Lerp的渐进减速 rb.MoveRotation(Quaternion.RotateTowards(rb.rotation, rotationTarget, rotateSpeed * Time.fixedDeltaTime)); rb.MovePosition(rb.position + transform.TransformDirection(Vector3.forward) * moveSpeed * Time.fixedDeltaTime); } else { // 无输入时锁定当前旋转,并清除角速度 rb.MoveRotation(rb.rotation); rb.angularVelocity = Vector3.zero; } }
内容的提问来源于stack exchange,提问作者Louis_gaming
相关产品推荐
相关产品推荐

