Unity无尽游戏玩家转向异常求助:应在Tile中央转向却从角落转向
问题:玩家在Tile角落而非中央转向的修复方案
这是一款无尽跑酷游戏,逻辑是通过Raycast检测脚下Tile,根据新生成Tile的方向让玩家转向(比如Tile右转,玩家同步右转)。但当前存在问题:玩家接触新Tile时,偶尔会在Tile的角落完成转向,而非预期的Tile中央位置。
相关代码
GroundSpawner 脚本
public class GroundSpawner : MonoBehaviour { Vector3 nextSpawnPoint; public GameObject[] tilePrefabs; public float TileCount; public int randomIndex; public void SpawnTile() { Quaternion targetRot = Quaternion.identity; if(Random.value > 0.5) { targetRot = Quaternion.Euler(0, 90, 0); } GameObject temp = Instantiate(tilePrefabs[randomIndex], nextSpawnPoint, targetRot); nextSpawnPoint = temp.transform.GetChild(1).transform.position; } void Start() { TileCount = tilePrefabs.Length; SpawnTile(); } public void ChooseTile() { randomIndex = (int)Random.Range(0, TileCount); print(randomIndex); } private void Update() { ChooseTile(); } }
GroundTile 脚本
每个平面对象挂载此脚本,预制体包含起点对象、nextSpawnPoint对象和平面,平面始终首尾相连。
public class GroundTile : MonoBehaviour { GroundSpawner groundSpawner; void Start() { groundSpawner = GameObject.FindObjectOfType<GroundSpawner>(); } private void OnTriggerEnter(Collider other) { groundSpawner.SpawnTile(); Destroy(gameObject, 3f); } private void Update() { } }
玩家控制器脚本(Update部分)
private void Update() { transform.position += moveVector * moveSpeed * Time.deltaTime; Ray ray = new Ray(transform.position, Vector3.down); if(Physics.Raycast(ray,out RaycastHit hitInfo,Mathf.Infinity,LayerMask.GetMask("Default"))) { if (hitInfo.transform.TryGetComponent(out GroundTile tile)) { Debug.Log(ray); moveVector = (tile.transform.position + tile.transform.forward); } } }
问题根源
- 转向触发时机错误:当前只要Raycast扫到新Tile就立刻更新移动方向,玩家刚踩进Tile边缘(角落)就会触发转向,完全没等到走到Tile中央。
- moveVector计算逻辑错误:
tile.transform.position + tile.transform.forward得到的是一个世界坐标点,不是方向向量,这会让玩家的移动目标混乱,进一步放大转向位置的偏移问题。 - Tile选择逻辑冗余:每帧调用
ChooseTile()会让randomIndex频繁变化,可能导致SpawnTile时选到的Tile和预期不符。
修复方案
1. 新增Tile中央触发器,控制转向时机
在每个Tile预制体里加一个空物体,给它加Collider并设为IsTrigger,把这个物体放在Tile正中央。只有当玩家进入这个中央触发器时,才更新移动方向。
修改后的GroundTile脚本:
public class GroundTile : MonoBehaviour { GroundSpawner groundSpawner; // 在Inspector里把Tile中央的触发对象拖到这里 public Collider centerTrigger; void Start() { groundSpawner = GameObject.FindObjectOfType<GroundSpawner>(); // 默认禁用中央触发器,避免误触发 centerTrigger.enabled = false; } private void OnTriggerEnter(Collider other) { // 玩家进入Tile起始触发器时,生成新Tile并启用中央触发器 if (other.CompareTag("Player") && other != centerTrigger) { groundSpawner.SpawnTile(); centerTrigger.enabled = true; } // 玩家走到Tile中央时,通知更新移动方向 else if (other.CompareTag("Player") && other == centerTrigger) { PlayerController player = other.GetComponent<PlayerController>(); if (player != null) { player.UpdateMoveDirection(transform.forward); } centerTrigger.enabled = false; } } private void OnDestroy() { Destroy(gameObject, 3f); } }
2. 修正玩家控制器的移动方向计算
把moveVector改成纯方向向量,移除原来的Raycast检测逻辑,改用中央触发器的回调来更新方向:
修改后的玩家控制器核心代码:
public class PlayerController : MonoBehaviour { public float moveSpeed; // 默认向前移动 private Vector3 moveVector = Vector3.forward; private void Update() { transform.position += moveVector * moveSpeed * Time.deltaTime; } // 供GroundTile调用的方向更新方法 public void UpdateMoveDirection(Vector3 newDirection) { moveVector = newDirection; } }
3. 优化Tile选择逻辑
只在生成Tile前选择随机索引,避免每帧刷新导致的逻辑混乱:
修改后的GroundSpawner脚本:
public class GroundSpawner : MonoBehaviour { Vector3 nextSpawnPoint; public GameObject[] tilePrefabs; public int randomIndex; public void SpawnTile() { // 生成Tile前才随机选择预制体 ChooseTile(); Quaternion targetRot = Quaternion.identity; if(Random.value > 0.5) { targetRot = Quaternion.Euler(0, 90, 0); } GameObject temp = Instantiate(tilePrefabs[randomIndex], nextSpawnPoint, targetRot); nextSpawnPoint = temp.transform.GetChild(1).transform.position; } void Start() { SpawnTile(); } public void ChooseTile() { randomIndex = Random.Range(0, tilePrefabs.Length); print(randomIndex); } // 移除Update中的ChooseTile调用 }
关键说明
- 中央触发器确保玩家只有走到Tile中间才会转向,彻底解决角落转向的问题。
- 把moveVector改为纯方向向量,避免坐标点导致的移动目标错误。
- 优化Tile选择时机,消除每帧刷新随机索引带来的潜在bug。
内容的提问来源于stack exchange,提问作者sevalllk
相关产品推荐
相关产品推荐

