You need to enable JavaScript to run this app. 如何正确使用Lerp实现位置、缩放及正交相机尺寸的平滑插值
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用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值超范围、单次执行无逐帧推进的问题。

可直接运行的正确实现

用协程承载整个过渡流程,逐帧推进插值进度,完全满足你要的三个平滑效果:

  1. 相机从当前位置平滑平移到第二玩家位置
  2. 相机正交大小从初始值10平滑缩到5
  3. 第二玩家缩放从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 11:15:04