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没有正对跑道前进方向,射线射向天空、地面或者跑道外,自然无法检测到障碍物。
修复方案
- 替换检测逻辑:用覆盖玩家碰撞体范围的
SphereCast代替单条射线,同时预留一帧移动距离避免高速隧穿,修正射线起点到角色控制器中心位置。 - 加调试可视化:运行时直接在Scene窗口查看射线实际发射状态,快速定位位置、方向、长度问题。
- 补全逻辑漏洞:死亡时同时停止横向移动速度,避免死亡后玩家还能左右滑动。
修复后的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
相关产品推荐
相关产品推荐

