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

Unity中使用Lerp实现相机移动旋转时过渡不平滑问题

相机卡顿问题分析与修复

你的代码里有几个关键问题导致了间歇性卡顿:

1. Update与协程的逻辑冲突

Update方法里每一帧都在强制设置相机的X位置:

transform.position = new(_character.transform.position.x - _distanceX, transform.position.y, transform.position.z);

而当你调用切换位置的方法时,协程同时在尝试用Lerp平滑移动相机。两者同时修改相机位置,必然导致画面抖动卡顿。

2. 协程的Lerp实现错误

  • while (_time != 1f):浮点数存在精度误差,_time几乎不可能精确等于1f,会导致协程无限运行,持续干扰相机状态。
  • Vector3.Lerp(transform.position, position, _time):这种基于当前帧位置的渐进式Lerp,而非从起始到目标的完整过渡,会导致移动速度不稳定,结合_time累加的方式,也无法准确控制平滑时长。
  • 旋转的Lerp参数_speed * _time逻辑混乱,_time是帧时间累加值,乘以速度后会导致旋转速度越来越快,不符合平滑需求。

修复方案

第一步:统一平滑逻辑,避免状态冲突

添加状态标记,确保切换位置时暂停普通跟随;同时重构协程的Lerp实现,保证过渡过程稳定可控:

using System.Collections;
using UnityEngine;

public class CameraMover : MonoBehaviour
{
    [SerializeField] private Vector3 _positionInShelter;
    [SerializeField] private Quaternion _rotationInShelter;
    [SerializeField] private GameObject _character;
    [SerializeField] private float _smoothFollowSpeed = 5f; // 日常跟随的平滑速度
    [SerializeField] private float _transitionDuration = 0.5f; // 切换位置/旋转的总时长

    private Quaternion _defaultRotation;
    private Vector3 _defaultPosition;
    private float _distanceX;
    private bool _isTransitioning; // 标记是否正在切换状态

    private void Awake()
    {
        _distanceX = _character.transform.position.x - transform.position.x;
        _defaultPosition = transform.position;
        _defaultRotation = transform.rotation;
    }

    private void Update()
    {
        // 仅在非切换状态下执行跟随逻辑
        if (!_isTransitioning)
        {
            Vector3 targetPosition = new Vector3(_character.transform.position.x - _distanceX, transform.position.y, transform.position.z);
            // 平滑跟随角色X轴
            transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * _smoothFollowSpeed);
        }
    }

    private IEnumerator TransitionTo(Vector3 targetPosition, Quaternion targetRotation)
    {
        _isTransitioning = true;
        Vector3 startPosition = transform.position;
        Quaternion startRotation = transform.rotation;
        float elapsedTime = 0f;

        // 按指定时长完成过渡,用 elapsedTime / 总时长 计算0-1的平滑进度
        while (elapsedTime < _transitionDuration)
        {
            elapsedTime += Time.deltaTime;
            float t = Mathf.Clamp01(elapsedTime / _transitionDuration);
            // 基于起始值和目标值做Lerp,保证过渡均匀平滑
            transform.position = Vector3.Lerp(startPosition, targetPosition, t);
            transform.rotation = Quaternion.Lerp(startRotation, targetRotation, t);
            yield return null;
        }

        // 强制设置到目标值,避免浮点数精度误差
        transform.position = targetPosition;
        transform.rotation = targetRotation;
        _isTransitioning = false;
    }

    public void CameraInShelterPosition()
    {
        StartCoroutine(TransitionTo(_positionInShelter, _rotationInShelter));
    }

    public void CameraDefaultPosition()
    {
        StartCoroutine(TransitionTo(_defaultPosition, _defaultRotation));
    }
}

关键改进点:

  • 新增_isTransitioning标记,彻底避免跟随逻辑与切换逻辑的冲突。
  • 协程使用起始值+目标值的Lerp方式,配合进度t控制过渡,保证时长稳定、速度均匀。
  • 普通跟随也改用平滑Lerp,移除硬赋值带来的突兀感。
  • 移除了无用的using static UnityEditor.PlayerSettings;引用,精简代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 01:29:59