如何制作兼具强制移动与平滑跟随的Crossy Roads克隆游戏相机
Crossy Roads 相机双模式切换逻辑修复方案
核心问题分析
- 状态标记更新时机错误:玩家Idle状态的判断未准确同步,或相机状态切换条件存在逻辑冲突
- 两种模式的执行逻辑未做清晰的互斥处理,导致无法正常切换
具体修复步骤
1. 修正PlayerControl中的Idle状态判断
确保只有当玩家无输入且完全静止时,才标记为Idle状态:
// PlayerControl.cs private Rigidbody2D rb; // 假设使用2D刚体,根据项目实际调整 public bool isIdle; private void Awake() { rb = GetComponent<Rigidbody2D>(); } private void Update() { // 检测是否有移动输入 bool hasMoveInput = Mathf.Abs(Input.GetAxis("Horizontal")) > 0.1f || Mathf.Abs(Input.GetAxis("Vertical")) > 0.1f; // 检测玩家是否静止 bool isStationary = rb.velocity.magnitude < 0.1f; // 同时满足无输入+静止,才判定为Idle isIdle = !hasMoveInput && isStationary; }
2. 重构CameraController的状态切换逻辑
将两种相机行为拆分为独立分支,用清晰的条件控制切换,且在LateUpdate中执行相机逻辑(避免与玩家移动帧不同步):
// CameraController.cs public Transform playerTransform; public float followLerpSpeed = 6f; public float idleMoveSpeed = 2.5f; // 玩家距离相机右边缘的阈值,到达后停止Idle移动 public float idleStopThreshold = 2.8f; private void LateUpdate() { if (playerTransform == null) return; PlayerControl player = playerTransform.GetComponent<PlayerControl>(); if (!player.isIdle) { // 玩家移动时:平滑Lerp跟随X轴 Vector3 targetPos = new Vector3(playerTransform.position.x, transform.position.y, transform.position.z); transform.position = Vector3.Lerp(transform.position, targetPos, followLerpSpeed * Time.deltaTime); } else { // 玩家Idle时:相机向右移动,直到玩家接近右边缘 float cameraRightEdge = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, 0)).x; if (cameraRightEdge - playerTransform.position.x > idleStopThreshold) { transform.Translate(Vector3.right * idleMoveSpeed * Time.deltaTime); } } }
3. 关键优化说明
- 使用LateUpdate:保证相机在玩家移动逻辑执行完成后再更新,消除画面抖动
- Idle判定加入输入检测:避免玩家按住方向键但未移动时,误触发Idle相机模式
- 明确Idle移动停止条件:通过相机视口边缘的世界坐标计算阈值,防止相机无限移动
验证标准
- 玩家移动时:相机平滑跟随,不触发Idle移动
- 玩家松开输入且静止后:相机自动向右移动,直到玩家接近右边缘后停止
- 玩家再次输入移动:相机立即切换回Lerp跟随模式
内容的提问来源于stack exchange,提问作者Zeid Tisnes
相关产品推荐
相关产品推荐

