如何正确使用Lerp实现位置、缩放及正交相机尺寸的平滑插值
Unity 中使用 Lerp 实现平滑过渡失效的修正方案
核心失效原因
你写的代码跑不出平滑效果,本质是两个硬错误:
- 插值参数取值违规:所有Lerp方法的第三个参数
interpolationT的合法取值范围是0~1,你传入的45远超这个范围,插值结果会被直接钳制到目标值,效果和瞬间跳转没有区别。 - 调用时机错误:所有Lerp逻辑写在了仅触发一次的
OnCollisionEnter2D回调里,哪怕参数写对了,单次执行只会完成一次极短的插值计算,完全达不到逐帧推进的动画效果。
逐行核对你的代码问题
对照你贴的实现,每一处Lerp的错漏:
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, 5, 45);:t值45超出0~1的合法区间,直接把视口大小拉到5,没有渐变过程。cam.transform.position = Vector3.Lerp(secondPlayer.transform.position, positionOfSecondPlayer, 45);:除了t值超范围,插值起点也选反了——你要的是从相机当前位置移到第二玩家所在位置,而不是从第二玩家位置往z轴为-10的固定点插值。secondPlayer.transform.localScale = Vector2.Lerp(secondPlayer.transform.localScale, scale, 45);:同样是t值超范围、单次执行无逐帧推进的问题。
可直接运行的正确实现
用协程承载整个过渡流程,逐帧推进插值进度,完全满足你要的三个平滑效果:
- 相机从当前位置平滑平移到第二玩家位置
- 相机正交大小从初始值10平滑缩到5
- 第二玩家缩放从0.1平滑涨到0.2
using System.Collections; using UnityEngine; public class Win : MonoBehaviour { public GameObject secondPlayer; public GameObject firstPlayer; public Camera cam; // 控制过渡总时长,数值越大动画越慢 public float transitionDuration = 2f; private void OnCollisionEnter2D(Collision2D collision) { // 非目标层碰撞直接跳过 if (collision.gameObject.layer != 3) return; // 触发后立即销毁第一玩家,启动过渡协程 Destroy(firstPlayer); StartCoroutine(SmoothTransitionCoroutine()); } private IEnumerator SmoothTransitionCoroutine() { // 提前缓存所有属性的初始值,避免动画过程中被其他逻辑干扰 float startCamSize = cam.orthographicSize; Vector3 startCamPos = cam.transform.position; Vector3 targetCamPos = new Vector3( secondPlayer.transform.position.x, secondPlayer.transform.position.y, -10f ); Vector3 startPlayerScale = secondPlayer.transform.localScale; Vector3 targetPlayerScale = new Vector3(0.2f, 0.2f, 1f); float elapsedTime = 0f; // 逐帧执行直到达到总过渡时长 while (elapsedTime < transitionDuration) { // 计算当前插值进度,保证t值始终落在0~1区间 float t = elapsedTime / transitionDuration; // 用SmoothStep做曲线优化,让动画启动和收尾更自然 t = Mathf.SmoothStep(0, 1, t); // 逐帧更新三个目标属性 cam.orthographicSize = Mathf.Lerp(startCamSize, 5f, t); cam.transform.position = Vector3.Lerp(startCamPos, targetCamPos, t); secondPlayer.transform.localScale = Vector3.Lerp(startPlayerScale, targetPlayerScale, t); // 累加帧间隔时间,等待下一帧 elapsedTime += Time.deltaTime; yield return null; } // 动画结束后强制对齐目标值,消除浮点误差带来的微小偏差 cam.orthographicSize = 5f; cam.transform.position = targetCamPos; secondPlayer.transform.localScale = targetPlayerScale; } }
实现注意点
- 不要把“当前属性值”作为Lerp的第一个参数,否则动画速度会随剩余距离缩短越来越慢,类似阻尼效果,不符合匀速过渡的预期。
- 协程结束后的强制赋值步骤不能省,避免因为帧率波动导致最终值和目标值有细微差别。
内容的提问来源于stack exchange,提问作者the_boy
相关产品推荐
相关产品推荐

