Unity C#实现相机(GameObject)面板间慢移动画需求
实现Unity相机在面板间的平滑慢移动画
嘿,我来帮你把相机的瞬间移动改成平滑的慢动画效果!你现在的代码是直接设置相机位置,所以会瞬间跳转,我们可以用Unity自带的插值方法来实现过渡动画,这里给你两种实用的方案:
方案一:用Vector3.MoveTowards实现帧率无关的平滑移动
这种方法适合通过移动速度来控制快慢,每帧逐步靠近目标位置,简单易上手:
public class MoveCanvas : MonoBehaviour { // 目标位置变量,用来存储要移动到的位置 private Vector3 _targetPosition; // 移动速度(单位:每秒移动的像素/距离),数值越小移动越慢 public float moveSpeed = 200f; // 定义各个面板的位置 private readonly Vector3 _resetPosition = new Vector3(0, 0, -10); private readonly Vector3 _leftPanelPosition = new Vector3(-205.5f, 0, 0); private readonly Vector3 _rightPanelPosition = new Vector3(205.5f, 0, 0); void Start() { // 初始化相机到初始位置 _targetPosition = _resetPosition; transform.position = _targetPosition; } void Update() { // 检测按键,设置对应目标位置 if (Input.GetKeyDown(KeyCode.A)) { SetTargetPosition(_leftPanelPosition); } if (Input.GetKeyDown(KeyCode.D)) { SetTargetPosition(_rightPanelPosition); } // 可以加个重置按键,按R回到初始位置 if (Input.GetKeyDown(KeyCode.R)) { SetTargetPosition(_resetPosition); } // 每帧平滑移动到目标位置,Time.deltaTime保证帧率无关 transform.position = Vector3.MoveTowards(transform.position, _targetPosition, moveSpeed * Time.deltaTime); } // 封装设置目标位置的方法,避免重复代码 private void SetTargetPosition(Vector3 newTarget) { _targetPosition = newTarget; } }
方案说明:
Vector3.MoveTowards会让相机每帧向目标位置移动固定距离,结合Time.deltaTime可以保证不管帧率高低,移动速度都是一致的- 你可以在Inspector面板调整
moveSpeed的值:数值越小,移动越慢;数值越大,移动越快
方案二:用协程+Vector3.Lerp实现固定时长的动画
这种方法适合通过动画时长精确控制移动快慢,比如固定0.5秒完成移动,适合需要统一动画节奏的场景:
public class MoveCanvas : MonoBehaviour { // 移动时长(单位:秒),数值越大移动越慢 public float moveDuration = 0.5f; // 标记是否正在移动,避免重复触发动画 private bool _isMoving = false; // 定义各个面板的位置 private readonly Vector3 _resetPosition = new Vector3(0, 0, -10); private readonly Vector3 _leftPanelPosition = new Vector3(-205.5f, 0, 0); private readonly Vector3 _rightPanelPosition = new Vector3(205.5f, 0, 0); void Start() { // 初始化相机到初始位置 transform.position = _resetPosition; } void Update() { // 只有不在移动时才响应按键 if (Input.GetKeyDown(KeyCode.A) && !_isMoving) { StartCoroutine(MoveToPosition(_leftPanelPosition)); } if (Input.GetKeyDown(KeyCode.D) && !_isMoving) { StartCoroutine(MoveToPosition(_rightPanelPosition)); } if (Input.GetKeyDown(KeyCode.R) && !_isMoving) { StartCoroutine(MoveToPosition(_resetPosition)); } } // 协程处理平滑移动逻辑 private IEnumerator MoveToPosition(Vector3 targetPos) { _isMoving = true; Vector3 startPos = transform.position; float elapsedTime = 0f; // 逐步插值移动,直到到达目标位置 while (elapsedTime < moveDuration) { // 用时间进度(0到1)做插值,实现平滑过渡 float progress = elapsedTime / moveDuration; // 如果想要更自然的缓动效果,可以用Mathf.SmoothStep(0, 1, progress)代替progress transform.position = Vector3.Lerp(startPos, targetPos, progress); elapsedTime += Time.deltaTime; yield return null; // 等待下一帧 } // 最后强制设置到目标位置,避免误差 transform.position = targetPos; _isMoving = false; } }
方案说明:
- 协程可以让我们在一段时间内逐步执行移动逻辑,
Vector3.Lerp根据时间进度(0到1)计算当前位置 - 如果你想要更自然的缓动效果(比如先慢后快,或者先快后慢),可以把
progress改成Mathf.SmoothStep(0, 1, progress),或者用AnimationCurve自定义速度曲线 _isMoving变量可以防止用户连续按键触发多个移动动画,避免相机位置混乱
额外小贴士:
- 确保相机的Z轴保持固定值(比如你的初始-10),因为UI相机的Z轴会影响UI元素的渲染层级,移动时不要改变Z轴
- 你可以把面板位置做成可配置的变量(比如用
[SerializeField]标记),这样可以直接在Inspector面板拖拽调整,不用硬编码数值
内容的提问来源于stack exchange,提问作者Ammar Ismaeel
相关产品推荐
相关产品推荐

