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
相关产品推荐
相关产品推荐

