解释Collision Detection模式的离散与连续差异
解读
国内Unity面试中,这道题常被用来快速判断候选人对物理系统底层行为的掌握深度。面试官真正想听的是:
- 你是否能用肉眼可见的现象把“穿模/漏检”和“性能消耗”说清楚;
- 你是否知道项目该在什么时候切模式,而不是死记文档。
答得太浅(只说“连续更准”)会被追问代价;答得太深(直接搬Box2D算法)又容易“炫技翻车”。用“场景+代价+解决方案”三段式最稳妥。
知识点
-
Discrete(离散检测)
- 逻辑:每帧只在当前位置做一次重叠判断,不推算运动轨迹。
- 表现:高速小物体容易“穿过”薄碰撞体,即所谓的“Tunneling”。
- 性能:只跑一次AABB broad-phase,移动端开销最低,是默认选项。
-
Continuous(连续检测)
- 逻辑:把本帧的线性轨迹扫一遍,用**TOI(Time of Impact)**算法提前找碰撞点,再回滚到接触瞬间。
- 表现:几乎杜绝Tunneling,适合高速子弹、足球、乒乓球这类“小而快”的对象。
- 性能:每帧额外跑一次** swept-based CCD**(Unity用Bullet的算法),CPU时间×2~×4,移动端发热明显。
-
切换原则
- 只给“会穿模”的刚体开Continuous,其余保持Discrete;
- Continuous Dynamic与Continuous Speculative只在3D物理里出现,2D只有Discrete与Continuous,不要混用术语;
- 墙体/地板永远Discrete,子弹/棒球才用Continuous,这是国内大厂代码规范里的硬性条目。
答案
“离散检测只在每帧最后时刻判断一次位置,高速物体会直接穿过薄碰撞体,但性能最低,是移动端的默认选择;连续检测会把本帧的运动轨迹扫一遍,用TOI算法提前找到碰撞点并回滚,几乎不会穿模,代价是CPU时间翻倍。实际项目里,只有子弹、足球这类高速刚体才手动切到Continuous,其余对象保持Discrete,靠分层+物理更新频率来平衡精度与帧率。”
拓展思考
-
如果面试官追问“为什么连续检测在2D里反而没有 speculative”,可以答:
“Unity 2D物理底层是Box2D,官方只实现了线性扫掠CCD,没有旋转扫掠,所以高速旋转的刀轮仍可能漏检,这时需要手动降低固定时间步长或增大碰撞体厚度。” -
若被问“热更新项目如何动态改检测模式”,可补充:
“通过HybridCLR或ILRuntime反射调用Rigidbody.collisionDetectionMode,但必须在生成阶段加[Preserve],防止裁剪,线上热更只敢把Discrete升Continuous,反向降级会触发物理缓存重建,可能造成1帧抖动。”