You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Cinemachine正交相机的平滑缩放?

Cinemachine正交相机平滑缩放实现方案

需求:让Cinemachine正交相机实现平滑缩放,按下按键后自动缓慢缩放到设定的最小(7.0f)/最大(14.0f)值,类似《最终幻想战术》的变焦效果,而非瞬间完成缩放。当前代码直接赋值正交大小导致瞬间变化,尝试添加Time.deltaTime后出现缩放过度且仍无平滑效果的问题。

方法一:协程实现固定时长平滑缩放

这种方式可以精确控制缩放完成的时间,按下一次按键后自动完成整个缩放过程:

using UnityEngine;
using Cinemachine;
using UnityEngine.InputSystem;
using System.Collections;

public class Zoom : MonoBehaviour
{
    public CinemachineVirtualCamera currentCamera;
    public float zoomDuration = 1.5f; // 缩放总时长(秒),可调整快慢
    private Coroutine _activeZoomCoroutine;

    public void OnZoomIn(InputAction.CallbackContext context)
    {
        if (context.started)
        {
            TriggerSmoothZoom(7.0f);
        }
    }

    public void OnZoomOut(InputAction.CallbackContext context)
    {
        if (context.started)
        {
            TriggerSmoothZoom(14.0f);
        }
    }

    private void TriggerSmoothZoom(float targetSize)
    {
        // 停止正在进行的缩放,避免冲突
        if (_activeZoomCoroutine != null)
        {
            StopCoroutine(_activeZoomCoroutine);
        }
        _activeZoomCoroutine = StartCoroutine(ZoomToTarget(targetSize));
    }

    private IEnumerator ZoomToTarget(float targetSize)
    {
        float startSize = currentCamera.m_Lens.OrthographicSize;
        float elapsedTime = 0f;

        while (elapsedTime < zoomDuration)
        {
            elapsedTime += Time.deltaTime;
            // 线性插值实现平滑过渡,用Mathf.SmoothStep可获得缓动效果
            currentCamera.m_Lens.OrthographicSize = Mathf.Lerp(startSize, targetSize, elapsedTime / zoomDuration);
            yield return null;
        }

        // 确保最终精确到达目标值
        currentCamera.m_Lens.OrthographicSize = targetSize;
        _activeZoomCoroutine = null;
    }
}

关键说明:

  • zoomDuration:控制缩放的快慢,值越小缩放越快,越大越慢
  • 协程ZoomToTarget:通过逐帧插值,在指定时间内将相机正交大小从当前值过渡到目标值
  • 每次触发缩放时先停止之前的协程,避免多次按键导致的冲突

方法二:Update帧更新实现平滑缩放

这种方式更简洁,通过每帧逐步逼近目标值,适合不需要严格固定时长的场景:

using UnityEngine;
using Cinemachine;
using UnityEngine.InputSystem;

public class Zoom : MonoBehaviour
{
    public CinemachineVirtualCamera currentCamera;
    public float zoomSpeed = 5f; // 每秒缩放的变化幅度,可调整快慢
    private float _targetOrthographicSize;

    private void Start()
    {
        // 初始化目标值为当前相机的正交大小
        _targetOrthographicSize = currentCamera.m_Lens.OrthographicSize;
    }

    private void Update()
    {
        // 每帧向目标值逼近,保证平滑过渡
        currentCamera.m_Lens.OrthographicSize = Mathf.MoveTowards(
            currentCamera.m_Lens.OrthographicSize, 
            _targetOrthographicSize, 
            zoomSpeed * Time.deltaTime
        );
    }

    public void OnZoomIn(InputAction.CallbackContext context)
    {
        if (context.started)
        {
            _targetOrthographicSize = 7.0f;
        }
    }

    public void OnZoomOut(InputAction.CallbackContext context)
    {
        if (context.started)
        {
            _targetOrthographicSize = 14.0f;
        }
    }
}

关键说明:

  • zoomSpeed:控制每秒缩放的变化量,值越大缩放越快
  • Mathf.MoveTowards:保证每帧的变化量基于Time.deltaTime,避免帧率波动影响缩放速度
  • 只需要设置目标值,Update会自动完成平滑过渡

为什么之前的尝试失败?

你之前添加Time.deltaTime后出现异常,大概率是因为只在按键触发时执行了一次缩放逻辑,没有在Update或协程中持续更新相机的正交大小,导致要么瞬间完成,要么计算错误出现过度缩放。上面两种方法都是通过逐帧更新实现平滑过渡,解决了这个问题。

内容的提问来源于stack exchange,提问作者NectarNoks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 06:45:14