Unity中Transform插值动画进度远超预期的问题求助
保险丝动画时长异常问题修复
问题场景
我需要让保险丝(fuse)对象平滑飞向保险丝盒(fuse box),通过Vector3/Quaternion.Lerp逐步适配位置和旋转,预期动画时长100秒,但实际几秒就完成了,无法看到正常过渡效果。
声明的变量
private Transform closestFuseBoxTransform = null; private Transform initialFuseTransform = null; private float fuseSnappingProgress = -1f; private float fuseSnapingAnimationTime = 100f; private float fuseSnappingBezierStrength = 1f;
当前Update方法代码
if (Input.GetKeyDown(KeyCode.Space)) { // 获取初始和目标Transform closestFuseBoxTransform = GetClosestObject(GameObject.FindGameObjectsWithTag("FuseDst")); initialFuseTransform = transform; // 启用动画逻辑 fuseSnappingProgress = 0f; Debug.Log(transform.rotation.eulerAngles); } if (fuseSnappingProgress >= 0f) { // 递增实时计时器 fuseSnappingProgress += Time.deltaTime / fuseSnapingAnimationTime; // 实现平滑过渡,利用x^y(y>0)在0<x<1时返回0<y<1的特性 float fuseSnappingProgressBezier = Mathf.Pow(fuseSnappingProgress, fuseSnappingBezierStrength); Debug.Log(fuseSnappingProgressBezier); // 使用初始位置、目标位置和计算出的fuseSnappingProgressBezier设置Transform值 transform.position = Vector3.Lerp(initialFuseTransform.position, closestFuseBoxTransform.position, fuseSnappingProgressBezier); transform.rotation = Quaternion.Lerp(initialFuseTransform.rotation, closestFuseBoxTransform.rotation, fuseSnappingProgressBezier); // 当动画完成100%时 if (fuseSnappingProgress >= 1f) { // 修正可能因大Time.deltaTime导致的进度跳变问题 transform.position = closestFuseBoxTransform.position; transform.rotation = closestFuseBoxTransform.rotation; // 关闭动画逻辑 fuseSnappingProgress = -1f; Debug.Log("Fuse snapped into closest Fuse Box"); } }
问题原因
核心问题是你把initialFuseTransform直接赋值为transform,这意味着它始终指向当前保险丝的Transform组件,而非动画启动时的初始状态。随着动画执行,initialFuseTransform.position会跟着保险丝的移动不断更新,导致Vector3.Lerp的起始点越来越接近目标点,动画自然会快速结束。
另外还有个拼写小错误:fuseSnapingAnimationTime少了一个字母p,虽不影响运行,但会增加维护混淆的风险。
解决方案
不要保存Transform引用,而是用单独变量存储动画启动时的初始位置和初始旋转值:
修改后的变量声明
private Transform closestFuseBoxTransform = null; private Vector3 initialFusePosition; // 存储动画启动时的初始位置 private Quaternion initialFuseRotation; // 存储动画启动时的初始旋转 private float fuseSnappingProgress = -1f; private float fuseSnappingAnimationTime = 100f; // 修正拼写错误,统一命名规范 private float fuseSnappingBezierStrength = 1f;
修改后的Update方法代码
if (Input.GetKeyDown(KeyCode.Space)) { // 获取目标Transform closestFuseBoxTransform = GetClosestObject(GameObject.FindGameObjectsWithTag("FuseDst")); // 保存动画启动瞬间的初始位置和旋转 initialFusePosition = transform.position; initialFuseRotation = transform.rotation; // 启用动画逻辑 fuseSnappingProgress = 0f; Debug.Log(transform.rotation.eulerAngles); } if (fuseSnappingProgress >= 0f) { // 递增实时计时器 fuseSnappingProgress += Time.deltaTime / fuseSnappingAnimationTime; // 限制进度最大值为1,避免帧率波动导致进度超标 fuseSnappingProgress = Mathf.Min(fuseSnappingProgress, 1f); // 实现平滑过渡 float fuseSnappingProgressBezier = Mathf.Pow(fuseSnappingProgress, fuseSnappingBezierStrength); // 使用保存的初始值进行插值计算 transform.position = Vector3.Lerp(initialFusePosition, closestFuseBoxTransform.position, fuseSnappingProgressBezier); transform.rotation = Quaternion.Lerp(initialFuseRotation, closestFuseBoxTransform.rotation, fuseSnappingProgressBezier); // 当动画完成时 if (fuseSnappingProgress >= 1f) { // 修正最终位置和旋转,确保完全对齐 transform.position = closestFuseBoxTransform.position; transform.rotation = closestFuseBoxTransform.rotation; // 关闭动画逻辑 fuseSnappingProgress = -1f; Debug.Log("保险丝已卡入最近的保险丝盒"); } }
额外优化点
- 修正变量名拼写错误,统一代码命名规范
- 添加
Mathf.Min限制进度最大值,避免异常情况 - 将日志改为中文,更贴合本地化需求
内容的提问来源于stack exchange,提问作者Cyklon 3000
相关产品推荐
相关产品推荐

