Unity 3D开发中OnCollisionEnter碰撞回调不触发问题求助
问题现象
编写的3D项目碰撞检测脚本无法正常触发OnCollisionEnter回调,对应脚本代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Collision : MonoBehaviour { private void OnCollisionEnter(UnityEngine.Collision other) { if(other.gameObject.tag == "Wrong") { print("test"); } } }
当前已知配置:参与碰撞的两个对象的BoxCollider组件isTrigger属性均设置为false。
疑问点
- 玩家使用胶囊体碰撞体是否会影响碰撞检测
- 玩家挂载的
Rigidbody组件isKinematic属性为True,且使用Character Controller实现移动逻辑,是否会导致回调不触发 - 未定位到问题根因,需要对应解决方案
根因说明
- 胶囊体作为玩家碰撞体不会影响碰撞检测,是Unity 3D角色开发的标准碰撞体配置,不存在兼容问题。
- 当前配置确实会导致
OnCollisionEnter无法触发,核心原因有两点:- 不符合Unity物理碰撞事件规则:两个碰撞体要触发
OnCollisionEnter回调,必须保证至少有一个碰撞体挂载非Kinematic状态的Rigidbody。两个Kinematic Rigidbody之间、Kinematic Rigidbody和无Rigidbody的静态碰撞体之间,都不会派发碰撞进入事件。 - 组件逻辑冲突:
CharacterController自带独立的碰撞检测逻辑,移动完全由该组件接管,不会走常规Rigidbody的物理碰撞事件派发流程。同时挂载Rigidbody和CharacterController属于典型的混用两套物理系统的错误写法,常规物理回调默认不会触发。
- 不符合Unity物理碰撞事件规则:两个碰撞体要触发
- 额外隐患:脚本类名直接命名为
Collision,和Unity内置的UnityEngine.Collision类重名,虽然当前参数写了全限定名没有触发编译错误,但后续开发很容易引发命名冲突。
可落地解决方案
- 优先推荐方案(适配现有CharacterController移动逻辑):
删掉玩家对象上挂载的Rigidbody组件,不要混用两套物理系统。CharacterController的碰撞事件不要用OnCollisionEnter监听,改用组件自带的OnControllerColliderHit回调实现碰撞判断,参考代码:
注意判断标签优先用using System.Collections; using System.Collections.Generic; using UnityEngine; // 建议把类名改成和引擎类不冲突的自定义名称 public class PlayerCollision : MonoBehaviour { private CharacterController _characterController; void Awake() { _characterController = GetComponent<CharacterController>(); } private void OnControllerColliderHit(ControllerColliderHit hit) { if(hit.gameObject.CompareTag("Wrong")) { print("test"); } } }CompareTag方法,比直接取tag字段判断性能更好,还能在标签不存在时抛出告警,避免手写标签名拼错的问题。 - 备选方案(适配常规物理系统回调):
删掉玩家对象上的CharacterController组件,将挂载的Rigidbody的isKinematic属性设为false,通过Rigidbody提供的MovePosition等API实现移动逻辑。此时只要保证两个碰撞对象至少有一个挂载非Kinematic Rigidbody,OnCollisionEnter就可以正常触发。 - 通用排查项:
打开Edit > Project Settings > Physics面板,检查碰撞矩阵中两个碰撞对象所属Layer的交互是否勾选,层交互被屏蔽也会导致碰撞事件不触发。
内容的提问来源于stack exchange,提问作者idk
相关产品推荐
相关产品推荐

