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

Unity无尽跑酷Raycast实现玩家障碍物碰撞检测失效问题

Unity无尽跑酷Raycast碰撞检测不触发问题修复

问题现象

开发无尽跑酷游戏时,挂载在玩家对象上的Physics.Raycast碰撞逻辑始终无法触发,玩家撞击障碍物后不会进入预期的死亡状态。
附原有实现代码:

public class Player : MonoBehaviour
{
    private CharacterController controller;

    public float speed;
    public float jumpHeight;
    private float jumpVelocity;
    public float gravity;

    public float rayRadius;
    public LayerMask layer;
    
    public float horizontalSpeed;
    private bool isMovingLeft;
    private bool isMovingRight;
    private bool isDead;

    void Start()
    {
        controller = GetComponent<CharacterController>();  
    }

    void Update()
   { 
        Vector3 direction = Vector3.forward * speed;

        if(controller.isGrounded)
        {
            if(Input.GetKeyDown(KeyCode.Space))
            {
                jumpVelocity = jumpHeight;

            }
            if(Input.GetKeyDown(KeyCode.RightArrow)&& transform.position.x  < 3.58f && !isMovingRight)
            {
                isMovingRight = true;
                StartCoroutine(RightMove());

            }
            if(Input.GetKeyDown(KeyCode.LeftArrow)&& transform.position.x > -3.58f && !isMovingLeft)
            {
                isMovingLeft = true;
                StartCoroutine(LeftMove());

            }
        }
        else
        {
            jumpVelocity -= gravity;
        }

        OnCollision();

        direction.y = jumpVelocity;

        controller.Move(direction * Time.deltaTime);
    }
    IEnumerator LeftMove()
    {
        for(float i = 0; i < 10; i += 0.1f)
        {
            controller.Move(Vector3.left * Time.deltaTime * horizontalSpeed);
            yield return null;
        }
        isMovingLeft = false;

    }

    IEnumerator RightMove()
    {
        for (float i = 0; i < 10; i += 0.1f)
        {
            controller.Move(Vector3.right * Time.deltaTime * horizontalSpeed);
            yield return null;
        }
        isMovingRight = false;

    }

    void OnCollision()
    {
        RaycastHit hit;

        if(Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, rayRadius, layer) && !isDead)
        {

            Debug.Log("GameOver!");
            speed = 0;

            jumpHeight = 0;
            isDead = true;
        }
    }
}

故障原因排查

按出现概率从高到低排序:

  • 检测方式缺陷:单条射线检测范围极窄,只要障碍物不在玩家中心正前方就会漏检,完全无法覆盖玩家的横向碰撞宽度,本身就不适合跑酷类游戏的碰撞判定。
  • 隧穿问题:如果rayRadius设置值小于玩家单帧前进距离,高速移动时会出现「上一帧射线还没碰到障碍物,下一帧玩家直接穿到障碍物后方」的情况,检测自然失效。
  • 射线起点偏移:如果玩家对象的坐标原点在模型脚部,射线会贴地发射,遇到有一定高度的障碍物时会直接从障碍物下方穿过,碰不到碰撞体。
  • 配置错误:要么障碍物所在层和脚本指定的检测层不匹配,要么障碍物没挂载Collider、Collider勾选了Is Trigger但没开启对应Physics查询开关,要么Unity Physics设置中关闭了对应层的碰撞交互。
  • 方向偏移:如果玩家对象存在旋转偏差,transform.forward没有正对跑道前进方向,射线射向天空、地面或者跑道外,自然无法检测到障碍物。

修复方案

  1. 替换检测逻辑:用覆盖玩家碰撞体范围的SphereCast代替单条射线,同时预留一帧移动距离避免高速隧穿,修正射线起点到角色控制器中心位置。
  2. 加调试可视化:运行时直接在Scene窗口查看射线实际发射状态,快速定位位置、方向、长度问题。
  3. 补全逻辑漏洞:死亡时同时停止横向移动速度,避免死亡后玩家还能左右滑动。
    修复后的OnCollision方法代码如下:
void OnCollision()
{
    RaycastHit hit;
    // 调试画线:Scene窗口显示红色检测范围,方便排查参数问题
    Debug.DrawRay(transform.position + Vector3.up * controller.height/2f, transform.forward * (rayRadius + speed * Time.deltaTime), Color.red, 0.1f);
    
    if (!isDead && Physics.SphereCast(
        origin: transform.position + Vector3.up * controller.height/2f, // 起点移到CharacterController中心,避免贴地漏检
        radius: controller.radius * 0.8f, // 检测半径匹配角色宽度,覆盖整个碰撞范围
        direction: transform.forward,
        hitInfo: out hit,
        maxDistance: rayRadius + speed * Time.deltaTime, // 长度预留一帧移动距离,解决高速隧穿
        layerMask: layer
    ))
    {
        Debug.Log("GameOver!");
        speed = 0;
        jumpHeight = 0;
        horizontalSpeed = 0; // 停止横向移动
        isDead = true;
    }
}

参数校准

  • Inspector面板中rayRadius设为0.2~0.5m即可,不需要过大
  • 确认所有障碍物都挂载了非Trigger类型的Collider,所在层和脚本设置的检测层完全匹配
  • 确认玩家对象Z轴正方向正对跑道前进方向

内容的提问来源于stack exchange,提问作者NIK 444

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 09:39:20