Unity2D的碰撞检测响应处理细节
Table of Contents
请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com
Unity中的2D碰撞/触发回调的触发规则遵循一下的规则
详细的触发规则
首先明确两个核心概念的区别:
- 碰撞(Collision):需要两个Collider2D都勾选
Is Trigger = false,且满足物理交互条件 - 触发(Trigger):至少一个Collider2D勾选
Is Trigger = true
1. 碰撞回调(OnCollisionEnter2D/Stay2D/Exit2D)的触发条件
要接收到碰撞回调,必须满足:
- 两个Collider2D都未勾选
Is Trigger - 至少其中一个 GameObject拥有 非静态 的Rigidbody2D组件(注意:Rigidbody2D不能设为
Kinematic+Is Kinematic且另一个也无Rigidbody2D,这种情况不会触发) - 两个Collider2D的
Layer层碰撞矩阵允许交互
2. 触发回调(OnTriggerEnter2D/Stay2D/Exit2D)的触发条件
要接收到触发回调,规则更宽松:
- 至少一个Collider2D勾选
Is Trigger - 满足以下任一条件即可:
- 其中一个GameObject有 非静态 的Rigidbody2D(可以是动态/运动学)
- 其中一个GameObject是 运动的静态物体(Static GameObject,且通过代码主动改变位置/旋转)
- 注意:两个纯静态(Static)且无Rigidbody2D的物体碰撞,不会触发任何回调
常见场景示例
为了让你更直观理解,这里列出几个典型场景:
| 场景 | A物体(Collider2D) | B物体(Collider2D) | 是否触发回调 |
|---|---|---|---|
| 1 | 有Rigidbody2D(动态) | 无Rigidbody2D | ✅(碰撞/触发都可) |
| 2 | 无Rigidbody2D | 有Rigidbody2D(动态) | ✅(碰撞/触发都可) |
| 3 | 无Rigidbody2D(静态) | 无Rigidbody2D(静态) | ❌(无任何回调) |
| 4 | 有Rigidbody2D(运动学) | 无Rigidbody2D | ✅(触发可,碰撞需B也有非运动学Rigidbody2D) |
关键补充
- 回调函数(如
OnCollisionEnter2D)必须写在有Collider2D的GameObject所挂载的脚本中,且脚本所在的GameObject需满足上述Rigidbody2D条件,否则接收不到回调。 - Rigidbody2D的
Body Type影响:Dynamic(动态):受物理力影响,是最常用的能触发回调的类型Kinematic(运动学):不受物理力影响,但主动移动时能触发触发回调Static(静态):等同于无Rigidbody2D的静态物体
总结
- 核心规则:要接收2D碰撞/触发回调,不能两个物体都没有Rigidbody2D且都是静态的,至少一个物体要有非静态的Rigidbody2D(触发回调允许运动学Rigidbody2D)。
- 简化记忆:日常开发中,给需要检测碰撞/触发的物体(或其中一个)挂载
Rigidbody2D(动态类型),就能稳定接收到回调。 - 触发vs碰撞:触发回调规则更宽松(运动学Rigidbody2D也可),碰撞回调要求更严格(至少一个动态Rigidbody2D)。
3D的Collider和Rigidbody也是遵循一样的规则吗
你问的这个问题很关键,3D的Collider和Rigidbody的碰撞/触发回调规则核心逻辑和2D一致,但在细节上有一些专属的差异,并不是完全一模一样。
3D vs 2D 核心规则对比
先明确最核心的共性,再讲差异:
1. 核心共性(和2D一致)
- 要接收到
OnCollisionEnter/Stay/Exit(碰撞)或OnTriggerEnter/Stay/Exit(触发)回调,不能两个物体都是“纯静态无刚体”:- 至少一个物体挂载非静态的Rigidbody(3D)/Rigidbody2D(2D);
- 两个纯静态(Static勾选)且无Rigidbody的物体碰撞,无论是否勾选Is Trigger,都不会触发任何回调。
2. 3D独有的关键差异
| 维度 | 2D(Rigidbody2D) | 3D(Rigidbody) |
|---|---|---|
| 刚体类型 | 有3种:Dynamic/Kinematic/Static | 只有2种:Dynamic/Kinematic(无Static类型,Static是物体的属性) |
| 静态物体处理 | Rigidbody2D设为Static ≈ 无刚体的静态物体 | 3D中“Static”是GameObject的勾选属性,而非Rigidbody的类型 |
| 运动学刚体碰撞规则 | Kinematic刚体+无刚体物体,碰撞回调不触发 | Kinematic刚体+无刚体物体,碰撞回调也不触发(和2D一致),但触发回调可触发 |
| 特殊限制 | 无额外限制 | Rigidbody的Is Kinematic勾选后,若要触发碰撞回调,需开启Collision Detection为Continuous(高版本Unity) |
| 静态碰撞器优化 | 自动归为静态碰撞器 | 勾选Static的物体,其Collider会被Unity优化为“静态碰撞器”,不参与物理模拟,仅用于检测 |
3D碰撞/触发回调的具体规则
1. 碰撞回调(OnCollisionXXX,Is Trigger=false)
触发条件(比2D略严格):
- 两个Collider都未勾选
Is Trigger; - 至少一个物体挂载Dynamic类型的Rigidbody(3D的Kinematic刚体和无刚体物体碰撞,不会触发碰撞回调);
- 层碰撞矩阵允许交互。
2. 触发回调(OnTriggerXXX,Is Trigger=true)
触发条件(和2D几乎一致):
- 至少一个Collider勾选
Is Trigger; - 满足以下任一条件:
- 其中一个物体有Dynamic/Kinematic类型的Rigidbody;
- 其中一个静态物体(勾选Static)被代码主动移动/旋转(无Rigidbody也可);
- 注意:两个纯静态(Static勾选)且无Rigidbody的物体,即使勾选Is Trigger,也不会触发回调。
3D专属的重要补充
- Static属性的影响:
3D中GameObject的
Static勾选后,其Collider会被Unity标记为“静态碰撞器”,用于烘焙导航网格、优化物理检测,但静态碰撞器无法主动触发碰撞/触发回调,必须靠动态刚体(Dynamic)的物体碰撞它才能触发。 - Rigidbody的Sleep状态: 3D的Rigidbody如果处于Sleep(休眠)状态(静止无受力),碰撞检测会被优化,可能暂时接收不到回调,唤醒后恢复(2D也有但3D更明显)。
- 碰撞检测模式:
3D的Rigidbody有
Collision Detection选项(Discrete/Continuous/Continuous Dynamic),用于解决高速物体穿模问题,2D的Rigidbody2D也有类似但选项更少。
示例:3D常见场景验证
| 场景 | A物体(Collider) | B物体(Collider) | 是否触发回调 |
|---|---|---|---|
| 1 | 有Dynamic Rigidbody | 无Rigidbody(Static勾选) | ✅(碰撞/触发都可) |
| 2 | 有Kinematic Rigidbody | 无Rigidbody | ❌(碰撞)/✅(触发,A主动移动时) |
| 3 | 无Rigidbody(Static) | 无Rigidbody(Static) | ❌(无任何回调) |
总结
- 核心逻辑一致:3D和2D的本质规则相同——“不能两个都是纯静态无刚体”,至少一个物体有非静态刚体才能触发回调。
- 关键差异:3D的Rigidbody无Static类型(Static是物体属性),且碰撞回调要求至少一个Dynamic刚体(2D碰撞回调也有此要求,但表述上2D有Static刚体类型易混淆)。
- 简化记忆:日常开发中,3D场景给需要检测碰撞/触发的物体挂载
Rigidbody(设为Dynamic),和2D一样能稳定接收到回调,无需纠结细节差异。