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

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);
        }
    }
}

问题根源

  1. 转向触发时机错误:当前只要Raycast扫到新Tile就立刻更新移动方向,玩家刚踩进Tile边缘(角落)就会触发转向,完全没等到走到Tile中央。
  2. moveVector计算逻辑错误:tile.transform.position + tile.transform.forward得到的是一个世界坐标点,不是方向向量,这会让玩家的移动目标混乱,进一步放大转向位置的偏移问题。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:10:35