Unity中用Vector3 Lerp移动相机如何实现缓入缓出并控制总时间
固定总时长的相机缓入缓出移动实现
原有代码的核心问题
要同时满足「严格按totalMovementTime指定时长抵达目标」和「平滑缓入缓出」两个要求,首先需要修正原代码的两个逻辑硬伤:
- 原代码将
transform.localPosition作为每帧插值的起点,是指数趋近的运动逻辑,根本无法卡准设定的总时长,甚至会因为浮点数精度问题,在离目标极近的位置持续漂移,触发不了循环退出条件 - 原代码直接把时间比值作为Lerp的插值系数,是完全匀速的线性运动,启动瞬间就达到最高速度、抵达终点瞬间直接刹停,没有任何速度平滑变化,自然没有缓入缓出效果
实现逻辑
- 协程启动时提前记录相机的固定起始位置,所有插值都在这个固定起始位置和目标位置之间计算,不跟每帧的当前位置绑定,从根源上避免总时长失控
- 计算严格绑定总时长的归一化线性进度
t = 累计移动时间 / totalMovementTime,范围落在0~1之间,保证累计时间走完设定值时,进度必然到100% - 对线性进度
t套用缓动函数,把匀速进度映射成「启动时从0逐步加速(缓入)、中途达到最高速度、临近终点逐步减速到0(缓出)」的速度曲线,用转换后的缓动值作为Lerp的插值系数 - 循环退出条件从「距离目标点的距离大于0」改成「累计移动时间小于总时长」,时间到点直接对齐目标位置,彻底解决漂移问题
修正后代码
public IEnumerator MoveToDestination () { float totalMovementTime = 2f; float currentMovementTime = 0f; // 协程启动时记录固定起始位置,避免插值基线漂移 Vector3 startCamPos = transform.localPosition; Vector3 targetCamPos = destinationCamPos; while (currentMovementTime < totalMovementTime) { currentMovementTime += Time.deltaTime; // 计算0-1范围的线性进度,严格和总时长绑定 float t = Mathf.Clamp01(currentMovementTime / totalMovementTime); // 三次方缓入缓出:t<0.5时加速(缓入),t>0.5时减速(缓出) float easedT; if (t < 0.5f) { easedT = 4 * t * t * t; } else { easedT = 1 - Mathf.Pow(-2 * t + 2, 3) / 2; } // 基于固定起止位置做插值,位置和缓动进度严格绑定 transform.localPosition = Vector3.Lerp(startCamPos, targetCamPos, easedT); yield return null; } // 时间到点直接对齐目标,消除累计浮点误差 transform.localPosition = targetCamPos; }
效果说明
- 全程移动总耗时严格等于
totalMovementTime的设定值,不管速度曲线怎么调整,都不会提前或延后抵达目标 - 启动相机移动时,速度从0逐步提升,不会出现突然窜动的生硬感;即将抵达目标位置时,速度逐步降低,最后速度为0时刚好停在目标点
- 如果觉得当前缓动的幅度不合适,可以替换不同阶数的缓动公式,只要是基于归一化
t计算的进度映射,都不会破坏总时长的控制逻辑
内容的提问来源于stack exchange,提问作者Pifo
相关产品推荐
相关产品推荐

