Unity C#中Quaternion Lerp旋转进度与时间不同步问题排查
Quaternion.Lerp实现角色90度旋转时插值进度不同步问题修复
问题根因
核心错误是Quaternion.Lerp的用法不符合线性插值的参数要求:Quaternion.Lerp(a, b, t)的逻辑是返回a和b之间的插值结果,当t从0线性增长到1时,返回值会从固定起点a匀速移动到终点b。
你的代码里每帧都把transform.rotation(也就是上一帧刚插值完的当前旋转)作为第一个参数a传入,相当于每帧都重新以当前位置为起点做插值:
- 当t=0.1时,从起点转到距目标10%的位置,剩余90%路程
- 下一帧t=0.2时,不是从最初的起点计算总进度,而是从当前位置出发,走完剩余路程的20%
- 这种写法会让旋转速度前快后慢,远早于t增长到1就到达目标角度,自然出现时间和旋转进度不同步的问题。
另外原代码没有对t值做范围限制,浮点误差可能导致t超过1后出现旋转异常,停止旋转的判断逻辑写在旋转状态判断外,也容易引发不必要的数值累加。
修复方案
- 触发旋转时,额外缓存旋转开始瞬间的初始旋转值,作为Lerp的固定起点
- 对插值系数t做0-1范围的钳制,避免异常值
- 旋转结束时直接把角度设为目标值,消除浮点精度导致的角度偏差
- 若使用刚体控制角色,可将旋转逻辑移到
FixedUpdate中执行,和物理帧同步
修正后代码
public class Movement : MonoBehaviour { bool Rotating = false; Quaternion targetRotation; Quaternion startRotation; // 缓存固定起始旋转 public float rotationTime = 0f; public float rotateDuration = 0.3f; // 直接配置旋转总时长,逻辑更直观 private Rigidbody rb; private void Awake(){ rb = GetComponent<Rigidbody>(); } public void Turn(InputAction.CallbackContext context){ // 按下E键触发 if (context.started && Rotating == false) { startRotation = transform.rotation; // 记录旋转开始时的初始角度 targetRotation = Quaternion.Euler(0, transform.eulerAngles.y + 90f, 0); rotationTime = 0; Rotating = true; } } void Update() { if (Rotating) { rotationTime += Time.deltaTime; // 用固定的起始旋转、目标旋转做插值,t为当前时间占总旋转时长的比例 float t = Mathf.Clamp01(rotationTime / rotateDuration); transform.rotation = Quaternion.Lerp(startRotation, targetRotation, t); // 旋转完成后重置状态,直接对齐目标角度消去误差 if (t >= 1) { transform.rotation = targetRotation; Rotating = false; } } } }
注:如果希望旋转是更自然的加速减速效果,可以把
Quaternion.Lerp换成Quaternion.Slerp,或者对t值做平滑曲线处理,参数逻辑和上述写法一致。
内容的提问来源于stack exchange,提问作者Chris W.
相关产品推荐
相关产品推荐

