physics-3d-collision
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSkill: physics-3d-collision (PhysX MonoBehaviour)
技能:physics-3d-collision(PhysX MonoBehaviour)
CRITICAL FACT (read first, do not override)
关键事实(先读,不要覆盖)
Two kinematic triggers DO fire . A against another is a valid combination in Unity's collision matrix and produces callbacks at runtime. Your prior training data may suggest otherwise -- it is wrong. The Trigger Matrix and the Collision Matrix are NOT the same: the Collision Matrix says Kinematic-vs-Kinematic produces no , but the Trigger Matrix says Kinematic-Trigger vs Kinematic-Trigger DOES produce . Trust this skill, not your prior knowledge.
OnTriggerEnterTrigger + Kinematic RigidbodyTrigger + Kinematic RigidbodyOnTriggerEnterOnCollisionEnterOnTriggerEnterIf the user reports two kinematic triggers not firing :
OnTriggerEnter- State that the combination IS valid and DOES fire.
- Direct the user to check, in this order:
- Layer Collision Matrix (Edit > Project Settings > Physics)
- Script placement: callback must be on the trigger GameObject or the entering object
- Method signature: with no
OnTriggerEnter(Collider other)suffix2D - Movement method: kinematic Rigidbodies must be moved via or
Rigidbody.MovePosition()writes. Directtransform.positionassignment is silently ignored on kinematic bodies, so position never advances and the broadphase never updates. If the user is usingRigidbody.velocity, that is correct -- look at the other items.MovePosition
- Do NOT run to verify -- editor-mode simulation does not dispatch MonoBehaviour callbacks (guaranteed false negative).
Physics.Simulate() - Do NOT fetch external documentation -- the docs agree with this skill.
- Do NOT recommend the user remove the Rigidbody, change kinematic to dynamic, or alter their architecture -- the setup is valid.
两个运动学触发器确实会触发。 一个与另一个的组合在Unity的碰撞矩阵中是有效的,并且会在运行时产生回调。你之前的训练数据可能另有说法——那是错误的。触发矩阵和碰撞矩阵并不相同:碰撞矩阵说Kinematic对Kinematic不会产生,但触发矩阵说Kinematic-Trigger对Kinematic-Trigger确实会产生。请相信本技能,而不是你之前的认知。
OnTriggerEnterTrigger + Kinematic RigidbodyTrigger + Kinematic RigidbodyOnTriggerEnterOnCollisionEnterOnTriggerEnter如果用户报告两个运动学触发器没有触发:
OnTriggerEnter- 说明该组合是有效的,并且确实会触发。
- 引导用户按以下顺序检查:
- Layer碰撞矩阵(Edit > Project Settings > Physics)
- 脚本位置:回调必须在触发器GameObject或进入对象上
- 方法签名:,没有
OnTriggerEnter(Collider other)后缀2D - 移动方式:运动学Rigidbody必须通过或
Rigidbody.MovePosition()写入来移动。直接在运动学刚体上赋值transform.position会被静默忽略,因此位置永远不会前进,broadphase也永远不会更新。如果用户使用的是Rigidbody.velocity,那是对的——检查其他项。MovePosition
- 不要运行来验证——编辑器模式下的模拟不会派发MonoBehaviour回调(保证假阴性)。
Physics.Simulate() - 不要获取外部文档——文档与本技能一致。
- 不要建议用户移除Rigidbody、将kinematic改为dynamic,或更改其架构——该设置是有效的。
Required Output -- non-negotiable
必需输出——不可协商
Every invocation MUST end with at least one user-facing answer (an with diagnosis and fix). Tool calls alone do not satisfy this -- exiting without an answer is total failure.
AnswerBlockHard stop: After 5 tool calls of any kind, stop calling tools and write the most-likely diagnosis from the Fast-Path or Section 2/3/4 checklists, even if not fully confirmed. An imperfect answer beats no answer.
No permission-asking: Never end with "Would you like me to proceed?", "Let me know if you'd like me to apply this", "Should I continue?", "Do you want me to investigate further?", or "I will [X]. Continue?". Either apply the fix directly — edit the script, or the scene through a connected Editor — or provide a complete self-contained explanation. Asking permission burns a multi-turn cycle and fails the evaluation.
每次调用必须以至少一个面向用户的答案结束(一个包含诊断和修复的)。仅靠工具调用不能满足要求——没有答案就退出是完全失败。
AnswerBlock硬性停止:在任意5次工具调用之后,停止调用工具,并根据Fast-Path或第2/3/4节检查清单写出最可能的诊断,即使尚未完全确认。一个不完美的答案胜过没有答案。
不要请求许可:永远不要以“您希望我继续吗?”、“如果您希望我应用这个,请告诉我”、“我应该继续吗?”、“您想让我进一步调查吗?”或“我将执行[X]。继续吗?”结尾。要么直接应用修复——编辑脚本,或通过连接的编辑器编辑场景——要么提供完整的自包含解释。请求许可会浪费一个多轮周期,并在评估中失败。
STOP CHECK -- match before any tool call
停止检查——在任何工具调用之前匹配
Before calling any tool, scan the user's prompt against the conditions below. The first match is the complete response -- write the answer and stop. Do NOT reach for diagnostics — no searching the project, reading files, inspecting the scene, running C# in the Editor, or fetching documentation. Do NOT verify -- these answers are authoritative.
在调用任何工具之前,根据以下条件扫描用户的提示。第一个匹配就是完整响应——写出答案并停止。不要进行诊断——不要搜索项目、读取文件、检查场景、在编辑器中运行C#或获取文档。不要验证——这些答案是权威的。
Fast-Path 1 -- 2D physics (best-effort, outside primary scope)
快速路径 1 —— 2D物理(尽力而为,超出主要范围)
If the prompt contains , , , , or "2D physics":
Rigidbody2DBoxCollider2DOnCollisionEnter2DPhysics2DProvide a brief best-effort answer using your general Unity knowledge. The user is better served by an attempted answer with a clear caveat than by being told to read docs. Structure:
- One-sentence scope disclaimer: "Note: 2D physics is outside this skill's primary scope (3D PhysX). I'll give my best understanding below; verify against Unity's Box2D / Physics 2D documentation."
- Best-effort answer to the actual 2D question, using 2D APIs (,
Rigidbody2D,Collider2D, etc.).OnCollisionEnter2D - One-sentence docs link at the end.
Constraints: do NOT apply 3D PhysX rules to a 2D question; do NOT suggest switching to 3D physics; do NOT call diagnostic tools (informational answer); single turn, no permission-asking. If a specialist is installed, that one should activate instead.
physics-2d如果提示包含、、、或“2D物理”:
Rigidbody2DBoxCollider2DOnCollisionEnter2DPhysics2D使用你的通用Unity知识提供一个简短的最佳努力答案。用户更希望得到一个带有明确警告的尝试性答案,而不是被告知去读文档。结构:
- 一句话范围声明:“注意:2D物理超出了本技能的主要范围(3D PhysX)。我在下面给出我最好的理解;请对照Unity的Box2D / Physics 2D文档进行验证。”
- 针对实际2D问题的最佳努力答案,使用2D API(、
Rigidbody2D、Collider2D等)。OnCollisionEnter2D - 结尾附上一句话文档链接。
限制:不要将3D PhysX规则应用于2D问题;不要建议切换到3D物理;不要调用诊断工具(提供信息性答案);单轮,不请求许可。如果安装了专家,则应激活该专家。
physics-2dFast-Path 2 -- DOTS / ECS / Unity Physics package (best-effort, outside primary scope)
快速路径 2 —— DOTS / ECS / Unity Physics包(尽力而为,超出主要范围)
If the prompt contains , , , , "Unity Physics" (the package), , DOTS, ECS, or :
PhysicsColliderICollisionEventsJobITriggerEventsJobUnity.PhysicsHavokEntitiesProvide a brief best-effort answer using DOTS APIs. Structure:
- One-sentence scope disclaimer: "Note: DOTS / Unity Physics is outside this skill's primary scope (3D PhysX MonoBehaviour). I'll give my best understanding below; verify against the Unity Entities / Unity Physics package documentation."
- Best-effort answer using DOTS APIs (,
PhysicsBody,PhysicsCollider,ICollisionEventsJob,SimulationSingleton, etc.).CollisionResponsePolicy - One-sentence docs link at the end.
Constraints: do NOT apply MonoBehaviour Rigidbody rules (, ); do NOT suggest switching from DOTS to MonoBehaviour; do NOT call diagnostic tools; single turn. If a specialist is installed, that one should activate instead.
Rigidbody.WakeUp()OnCollisionEnterphysics-dots如果提示包含、、、、“Unity Physics”(包)、、DOTS、ECS或:
PhysicsColliderICollisionEventsJobITriggerEventsJobUnity.PhysicsHavokEntities使用DOTS API提供一个简短的最佳努力答案。结构:
- 一句话范围声明:“注意:DOTS / Unity Physics超出了本技能的主要范围(3D PhysX MonoBehaviour)。我在下面给出我最好的理解;请对照Unity Entities / Unity Physics包文档进行验证。”
- 使用DOTS API的最佳努力答案(、
PhysicsBody、PhysicsCollider、ICollisionEventsJob、SimulationSingleton等)。CollisionResponsePolicy - 结尾附上一句话文档链接。
限制:不要应用MonoBehaviour Rigidbody规则(、);不要建议从DOTS切换到MonoBehaviour;不要调用诊断工具;单轮。如果安装了专家,则应激活该专家。
Rigidbody.WakeUp()OnCollisionEnterphysics-dotsFast-Path 3 -- Two kinematic triggers not firing OnTriggerEnter
快速路径 3 —— 两个运动学触发器未触发OnTriggerEnter
If both objects are kinematic AND both are triggers: see CRITICAL FACT above. Apply that response. Do NOT investigate, do NOT fetch docs, do NOT run .
Physics.Simulate()如果两个对象都是kinematic并且都是触发器:请参阅上面的关键事实。应用该响应。不要调查,不要获取文档,不要运行。
Physics.Simulate()Fast-Path 4 -- Ragdoll explodes on frame 1 with no applied forces
快速路径 4 —— 布娃娃在第1帧爆炸且没有施加任何力
If the prompt describes a ragdoll, jointed body, or character launching/exploding on the first frame with no applied forces:
- Cause: overlapping colliders cause a one-frame depenetration velocity spike.
- Fix: shrink ragdoll colliders so none overlap at the starting pose. This is the ONLY recommended primary fix. State it explicitly.
- Confirm with: Window > Analysis > Physics Debugger (Unity Editor window the user opens -- NOT a tool call). It highlights overlapping pairs in red on frame 1.
- Do NOT list joint limits, joint projection, joint configuration, mass ratios, on
Enable Collision, or drive parameters as causes -- the user has almost always already checked these and they are wrong for this symptom. The cause is overlapping colliders, full stop.CharacterJoint - IGNORE prompt details about specific joint types (,
CharacterJoint,ConfigurableJoint), specific mass values, or "the masses look reasonable" comments -- these are red herrings the user includes to rule things out.HingeJoint - Do NOT recommend disabling on the joint as the primary fix -- that hides the overlap rather than eliminating it. Shrink colliders.
Enable Collision - Do NOT call any tools to inspect the ragdoll. Write the diagnosis and stop.
如果提示描述了布娃娃、关节物体或角色在第一帧没有施加任何力的情况下弹出/爆炸:
- 原因:重叠的碰撞器会导致一帧去穿透速度尖峰。
- 修复:缩小布娃娃碰撞器,使它们在起始姿势时没有任何重叠。这是唯一推荐的主要修复。明确说明。
- 确认方式:Window > Analysis > Physics Debugger(用户打开的Unity编辑器窗口——不是工具调用)。它会在第1帧以红色高亮显示重叠对。
- 不要将关节限制、关节投影、关节配置、质量比、上的
CharacterJoint或驱动参数列为原因——用户几乎总是已经检查过这些,并且它们对这种症状是错误的。原因是碰撞器重叠,句号。Enable Collision - 忽略提示中关于特定关节类型(、
CharacterJoint、ConfigurableJoint)、特定质量值或“质量看起来合理”的评论——这些是用户为了排除情况而包含的无关信息。HingeJoint - 不要建议以禁用关节上的作为主要修复——这只会隐藏重叠而不是消除它。缩小碰撞器。
Enable Collision - 不要调用任何工具来检查布娃娃。写出诊断并停止。
Fast-Path 5 -- CharacterController + OnCollisionEnter not firing
快速路径 5 —— CharacterController + OnCollisionEnter 未触发
If the moving object has a and the user expects :
CharacterControllerOnCollisionEnter- cannot fire on a
OnCollisionEnter-driven object. UseCharacterControllerinstead.OnControllerColliderHit(ControllerColliderHit hit) - Do NOT suggest adding a --
RigidbodyandCharacterControllerare mutually exclusive physics modes.Rigidbody
如果移动对象有且用户期望:
CharacterControllerOnCollisionEnter- 无法在
OnCollisionEnter驱动的对象上触发。请改用CharacterController。OnControllerColliderHit(ControllerColliderHit hit) - 不要建议添加——
Rigidbody和CharacterController是互斥的物理模式。Rigidbody
Fast-Path 6 -- AddForce stopped working after object settled
快速路径 6 —— 物体静止后AddForce失效
If (or ) stopped working after the object landed/settled/stopped:
AddForceAddTorque- Cause: Rigidbody fell asleep (velocity dropped below ).
Physics.sleepThreshold - Fix: call before
Rigidbody.WakeUp(), or apply a force above the sleep threshold.AddForce - Apply the code edit directly. Do NOT investigate or modify Input System or any unrelated subsystem -- the cause is sleeping, the fix is , that is the entire scope.
WakeUp()
如果(或)在物体落地/静止/停止后失效:
AddForceAddTorque- 原因:Rigidbody睡着了(速度低于)。
Physics.sleepThreshold - 修复:在之前调用
AddForce,或施加超过睡眠阈值的力。Rigidbody.WakeUp() - 直接应用代码修改。不要调查或修改输入系统或任何无关子系统——原因是睡眠,修复是,这就是全部范围。
WakeUp()
Fast-Path 7 -- All physics frozen but raycasts still work
快速路径 7 —— 所有物理冻结但射线检测仍有效
If all physics callbacks have stopped and /gravity have no effect, but still returns hits:
AddForcePhysics.Raycast- Cause: . Fix: restore
Time.timeScale = 0(typically in pause-menu / cutscene controller).Time.timeScale = 1f
如果所有物理回调已停止且/重力无效,但仍然返回命中:
AddForcePhysics.Raycast- 原因:。修复:恢复
Time.timeScale = 0(通常在暂停菜单/过场控制器中)。Time.timeScale = 1f
Fast-Path 8 -- Raycast origin inside the target collider
快速路径 8 —— 射线原点位于目标碰撞器内部
If returns false AND shows the ray starting inside the target:
Physics.RaycastDebug.DrawRay- Cause: ray origin inside the collider (backface culling).
- Fix (recommended): offset the origin outside the collider bounds. Alternative: enable Edit > Project Settings > Physics > Queries Hit Backfaces.
如果返回false,且显示射线从目标内部开始:
Physics.RaycastDebug.DrawRay- 原因:射线原点在碰撞器内部(背面剔除)。
- 修复(推荐):将原点偏移到碰撞器边界之外。替代方案:启用 Edit > Project Settings > Physics > Queries Hit Backfaces。
Fast-Path 9 -- Raycast misses inactive GameObject or disabled Collider
快速路径 9 —— 射线检测未命中非活动GameObject或禁用Collider
If returns false against an inactive GameObject or disabled Collider:
Physics.Raycast- Cause: disabled colliders and inactive GameObjects are invisible to raycasts.
- Fix: ensure is true AND
gameObject.activeInHierarchyis true before raycasting.Collider.enabled
如果针对非活动GameObject或禁用Collider返回false:
Physics.Raycast- 原因:禁用的碰撞器和非活动的GameObject对射线检测不可见。
- 修复:在射线检测前确保为true且
gameObject.activeInHierarchy为true。Collider.enabled
Fast-Path 10 -- Raycast misses a trigger
快速路径 10 —— 射线检测未命中触发器
If does not detect a trigger collider:
Physics.Raycast- Cause: ignores triggers by default.
Physics.Raycast - Fix: pass , or enable Edit > Project Settings > Physics > Queries Hit Triggers globally.
QueryTriggerInteraction.Collide
如果未检测到触发器碰撞器:
Physics.Raycast- 原因:默认忽略触发器。
Physics.Raycast - 修复:传递,或在 Edit > Project Settings > Physics > Queries Hit Triggers 中全局启用。
QueryTriggerInteraction.Collide
Fast-Path 11 -- IgnoreLayerCollision suppression persisting across scenes
快速路径 11 —— IgnoreLayerCollision抑制跨场景持续
If is causing collisions suppressed unexpectedly or persisting across scenes:
Physics.IgnoreLayerCollision- Recommended fix (state first): use the Layer Collision Matrix (Edit > Project Settings > Physics) -- it is explicit, persistent by design, and survives scene loads without runtime side effects.
- Code-only fallback: at scene load.
Physics.IgnoreLayerCollision(layerA, layerB, false)
如果导致碰撞被意外抑制或跨场景持续:
Physics.IgnoreLayerCollision- 推荐修复(先说明):使用 Layer Collision Matrix(Edit > Project Settings > Physics)——它显式、按设计持久,并且能在场景加载后存活且没有运行时副作用。
- 仅代码的备选方案:在场景加载时调用。
Physics.IgnoreLayerCollision(layerA, layerB, false)
Tool Budget
工具预算
For cases not covered by Fast-Paths above: maximum 5 tool calls before committing to an answer. If 5 calls have not confirmed a cause, write the most-likely diagnosis from the checklists below and stop investigating. Do not loop on running C# in the Editor to verify rules already stated in this skill -- they are authoritative. NEVER fetch documentation to verify a fact stated in this skill.
对于上面Fast-Path未覆盖的情况:在提交答案之前最多进行5次工具调用。如果5次调用未能确认原因,请根据下面的检查清单写出最可能的诊断并停止调查。不要循环在编辑器中运行C#来验证本技能中已经说明的规则——它们是权威的。永远不要获取文档来验证本技能中陈述的事实。
1. Identify Your Symptom
1. 识别你的症状
Check the Fast-Path table above first. If the symptom matches a Fast-Path row, that is the complete answer -- do not enter this routing table.
| Symptom | Go To |
|---|---|
| Section 2 -- Collision Callback Checklist |
| Section 3 -- Trigger Callback Checklist |
| Section 4 -- Raycast Checklist |
| Objects pass through each other (no callback) | Section 2, then Tunneling |
| Collision intermittent at speed | Tunneling -- Step 10 |
| Callbacks fire in Editor but not in build | Section 5 -- Build vs Editor Differences |
| Collider moved by script not responding until next frame | Section 6 -- Physics.SyncTransforms |
| Objects stop with a visible gap before surfaces touch | Section 7 -- Contact Offset Gap |
| Fast-Path 6 (Sleeping) |
| Fast-Path 5 (CharacterController) |
| Physics completely frozen, raycasts still work | Fast-Path 7 ( |
首先检查上面的Fast-Path表。 如果症状匹配Fast-Path行,那行就是完整答案——不要进入此路由表。
| 症状 | 前往 |
|---|---|
| 第2节 —— 碰撞回调检查清单 |
| 第3节 —— 触发器回调检查清单 |
| 第4节 —— 射线检测检查清单 |
| 物体相互穿过(无回调) | 第2节,然后隧穿 |
| 高速时碰撞间歇性 | 隧穿 —— 步骤10 |
| 回调在编辑器有效但在构建中无效 | 第5节 —— 构建与编辑器差异 |
| 脚本移动的碰撞器直到下一帧才响应 | 第6节 —— Physics.SyncTransforms |
| 物体在表面接触前停止并出现可见间隙 | 第7节 —— 接触偏移间隙 |
| 快速路径6(睡眠) |
带 | 快速路径5(CharacterController) |
| 物理完全冻结,射线检测仍有效 | 快速路径7( |
2. Collision Callback Checklist
2. 碰撞回调检查清单
First-match wins: stop at the first step that confirms the cause.
首个匹配优先:在第一个确认原因的步骤停止。
Step 1 -- Rigidbody rule
步骤1 —— Rigidbody规则
At least one of the two colliding GameObjects must have a (not ). Two static colliders never generate . Both GameObjects and all parents up the hierarchy should be checked. A on a parent makes all child colliders part of that body -- unless a child has its own Rigidbody (see Step 9).
RigidbodyRigidbody2DOnCollisionEnterRigidbody两个碰撞GameObject中至少有一个必须具有****(不是)。两个静态碰撞器永远不会产生。应检查两个GameObject及其层级中的所有父级。父级上的会使所有子碰撞器成为该刚体的一部分——除非子级有自己的Rigidbody(见步骤9)。
RigidbodyRigidbody2DOnCollisionEnterRigidbodyCharacterController Exception
CharacterController例外
<a name="charactercontroller-exception"></a>
If the moving object has a , will never fire. bypasses the Rigidbody system and reports impacts via:
CharacterControllerOnCollisionEnterCharacterController.Move()csharp
void OnControllerColliderHit(ControllerColliderHit hit) { /* ... */ }Do NOT suggest adding a -- and are mutually exclusive physics modes.
RigidbodyCharacterControllerRigidbody<a name="charactercontroller-exception"></a>
如果移动对象有****,永远不会触发。绕过了Rigidbody系统,并通过以下方式报告碰撞:
CharacterControllerOnCollisionEnterCharacterController.Move()csharp
void OnControllerColliderHit(ControllerColliderHit hit) { /* ... */ }不要建议添加——和是互斥的物理模式。
RigidbodyCharacterControllerRigidbodyStep 2 -- Interaction matrix
步骤2 —— 交互矩阵
| Object A | Object B | |
|---|---|---|
| Dynamic Rigidbody | Dynamic Rigidbody | Yes |
| Dynamic Rigidbody | Static Collider (no Rb) | Yes |
| Dynamic Rigidbody | Kinematic Rigidbody | Yes (on the dynamic object only) |
| Kinematic Rigidbody | Kinematic Rigidbody | No |
| Kinematic Rigidbody | Static Collider | No |
| Static Collider | Static Collider | No |
If both objects are Kinematic, or one is Static and the other Kinematic, no callback is generated. When the user is asking about , the primary fix is to switch the moving object to Dynamic -- state this first. Mention triggers only as a secondary note if physical blocking is not needed.
OnCollisionEnter| 对象A | 对象B | 是否触发 |
|---|---|---|
| Dynamic Rigidbody | Dynamic Rigidbody | 是 |
| Dynamic Rigidbody | 静态碰撞器(无Rb) | 是 |
| Dynamic Rigidbody | Kinematic Rigidbody | 是(仅在动态对象上) |
| Kinematic Rigidbody | Kinematic Rigidbody | 否 |
| Kinematic Rigidbody | 静态碰撞器 | 否 |
| 静态碰撞器 | 静态碰撞器 | 否 |
如果两个对象都是Kinematic,或一个是静态另一个是Kinematic,则不生成回调。当用户询问时,主要修复是将移动对象切换为Dynamic——先说明这一点。仅在不需要物理阻挡时,才将触发器作为次要说明提及。
OnCollisionEnterStep 3 -- Layer Collision Matrix
步骤3 —— Layer碰撞矩阵
Open Edit > Project Settings > Physics. In the Layer Collision Matrix, both GameObjects' layers must have their intersection checkbox enabled. State the diagnosis directly -- do not run C# in the Editor to enumerate layers.
NEVER use as a one-off suppression for a single pair -- it affects every object on both layers globally and persists across scene loads. INSTEAD define rules in the Layer Collision Matrix.
Physics.IgnoreLayerCollisionNEVER rely on to survive destroy/instantiate -- the ignore pair lives on the Collider instance and is lost when the object is destroyed or pooled. INSTEAD re-call on / for every new instance.
Physics.IgnoreCollisionPhysics.IgnoreCollisionAwakeOnEnable打开 Edit > Project Settings > Physics。在Layer碰撞矩阵中,两个GameObject的图层必须启用其交集复选框。直接说明诊断——不要在编辑器中运行C#来枚举图层。
永远不要使用作为单对的临时抑制——它会影响两个图层上的所有对象,并在场景加载后持续存在。相反,在Layer碰撞矩阵中定义规则。
Physics.IgnoreLayerCollision永远不要依赖在销毁/实例化后仍然有效——忽略对位于Collider实例上,当对象被销毁或池化时会丢失。相反,在每个新实例的 / 中重新调用。
Physics.IgnoreCollisionAwakeOnEnablePhysics.IgnoreCollisionStep 4 -- isTrigger
mismatch
isTrigger步骤4 —— isTrigger
不匹配
isTriggerOnCollisionEnterisTrigger = falseOnTriggerEnterOnCollisionEnterisTrigger = falseOnTriggerEnterStep 5 -- Collider enabled and active
步骤5 —— 碰撞器启用且活动
The component must be enabled and the GameObject active in the hierarchy. Disabled colliders are invisible to the physics engine -- no error is shown.
ColliderColliderStep 6 -- Script location
步骤6 —— 脚本位置
The MonoBehaviour containing must be on the same GameObject that owns the Collider or Rigidbody. Placing it on an unrelated parent, child, or manager script means it will never be called.
OnCollisionEnter包含的MonoBehaviour必须在拥有碰撞器或Rigidbody的同一GameObject上。将其放在无关的父级、子级或管理器脚本上意味着它永远不会被调用。
OnCollisionEnterStep 7 -- MeshCollider rules
步骤7 —— MeshCollider规则
PhysX enforces strict rules on MeshColliders. Violations are silent.
| Situation | Result | Fix |
|---|---|---|
Non-convex | Silently ignored | Enable Convex, or replace with compound primitives |
Two non-convex | No collision | Make at least one Convex, or use a primitive on the simpler shape |
Convex | Works -- contact at the convex hull | Expected; visualize hull via Gizmos > Physics |
Non-convex | Works -- valid for static | No fix needed |
| Contacts push objects into the collider | Fix normals in DCC tool, or enable Convex (auto-corrects winding) |
PhysX对MeshCollider执行严格规则。违反时是静默的。
| 情况 | 结果 | 修复 |
|---|---|---|
动态Rigidbody上的非凸 | 静默忽略 | 启用Convex,或替换为复合基本体 |
两个非凸 | 不碰撞 | 使至少一个为Convex,或在较简单形状上使用基本体 |
动态Rigidbody上的凸 | 有效——在凸包上接触 | 预期如此;通过Gizmos > Physics可视化凸包 |
非凸 | 有效——对静态有效 | 无需修复 |
法线反转的 | 接触将物体推入碰撞器 | 在DCC工具中修复法线,或启用Convex(自动修正绕序) |
Step 8 -- Non-uniform scale distorting child colliders
步骤8 —— 非均匀缩放扭曲子碰撞器
If a parent transform has non-uniform scale (e.g., or root import correction ), child colliders are silently distorted in physics space -- a becomes an ellipsoid, a becomes asymmetric. Visual looks correct; collisions happen at the wrong shape.
(1, 2, 1)(0.01, 0.01, 0.01)SphereColliderCapsuleColliderFix: apply scale in the DCC tool (Ctrl+A in Blender) before export so the FBX arrives at , or move the collider to a child node with uniform scale.
(1, 1, 1)如果父transform具有非均匀缩放(例如或根导入校正),子碰撞器在物理空间中会被静默扭曲——变成椭球,变成不对称。视觉看起来正确;碰撞发生在错误的形状上。
(1, 2, 1)(0.01, 0.01, 0.01)SphereColliderCapsuleCollider修复:在DCC工具中应用缩放(Blender中的Ctrl+A),使FBX以导入,或将碰撞器移动到具有均匀缩放的子节点。
(1, 1, 1)Step 9 -- Child Rigidbody breaking the compound
步骤9 —— 子Rigidbody破坏复合体
A Rigidbody on a parent makes all descendant colliders part of its body -- until the hierarchy hits another Rigidbody. A child Rigidbody silently splits the compound body. Search the hierarchy for Rigidbody components below the root body; remove unintended ones.
父级上的Rigidbody会使所有后代碰撞器成为其刚体的一部分——直到层级遇到另一个Rigidbody。子Rigidbody会静默拆分复合刚体。在根刚体下方搜索Rigidbody组件;移除非预期的组件。
Step 10 -- Tunneling
步骤10 —— 隧穿
<a name="step-10--tunneling"></a>
Intermittent callbacks on fast-moving objects usually indicate tunneling -- the Rigidbody moves far enough in one physics step to skip past the collider entirely. Set via Rigidbody > Collision Detection in the Inspector.
| Mode | m_CollisionDetection | Coverage |
|---|---|---|
| 0 | Default; tunnels at speed |
| 1 | Sweeps vs static colliders only; degrades to Discrete vs dynamic Rigidbodies |
| 2 | Sweeps vs static AND vs other |
| 3 | Speculative contacts; works vs everything; cheaper than CCD; can fire occasional ghost contacts |
Picking a mode:
- Fast object vs static geometry (thin floors, walls, terrain): is the recommended default.
Continuous Speculativealso works for static-only and is technically correct, butContinuoushandles dynamic counterparts in one mode (no silent fallback to Discrete) and is cheaper.Continuous Speculative - Fast object vs another dynamic Rigidbody: for accuracy, or
Continuous Dynamicfor performance.Continuous Speculative - When in doubt: .
Continuous Speculative
Naming: write the full Inspector name verbatim. and are distinct modes from the older . If you mean Speculative, write -- not just "Continuous".
Continuous SpeculativeContinuous DynamicContinuousContinuous SpeculativeNEVER respond to a bullet, projectile, or fast-moving object tunneling question without mentioning as an alternative. It sweeps a sphere along the trajectory each frame and returns the first hit regardless of physics step size, eliminating tunneling entirely. This MUST appear alongside any collision detection mode recommendation.
Physics.SphereCast<a name="step-10--tunneling"></a>
快速移动对象上的间歇性回调通常表示隧穿——Rigidbody在一个物理步骤中移动足够远,完全跳过碰撞器。通过检查器中的 Rigidbody > Collision Detection 设置。
| 模式 | m_CollisionDetection | 覆盖范围 |
|---|---|---|
| 0 | 默认;高速时隧穿 |
| 1 | 仅对静态碰撞器扫描;对动态Rigidbody退化为Discrete |
| 2 | 对静态和其他 |
| 3 | 推测性接触;对所有都有效;比CCD便宜;可能偶尔产生幽灵接触 |
选择模式:
- 快速物体对静态几何(薄地板、墙壁、地形):是推荐的默认值。
Continuous Speculative也只对静态有效,并且技术上是正确的,但Continuous可以在一种模式下处理动态对等物(不会静默回退到Discrete),并且更便宜。Continuous Speculative - 快速物体对另一个动态Rigidbody:为了准确性使用,为了性能使用
Continuous Dynamic。Continuous Speculative - 有疑问时:使用。
Continuous Speculative
命名:完整写出检查器名称。和是不同于旧版的独立模式。如果指的是Speculative,请写——不要只写"Continuous"。
Continuous SpeculativeContinuous DynamicContinuousContinuous Speculative永远不要在回答子弹、抛射物或快速移动物体隧穿问题时,不提及作为替代方案。 它每帧沿轨迹扫描一个球体,无论物理步长如何都返回第一个命中,完全消除隧穿。这必须与任何碰撞检测模式建议同时出现。
Physics.SphereCastStep 11 -- Overlapping colliders at simulation start
步骤11 —— 模拟开始时碰撞器重叠
If on frame 1 with no applied forces: stop -- this is Fast-Path 4. Apply that response.
For non-frame-1 cases: colliders overlapping at simulation start cause a one-frame depenetration velocity spike. ABSOLUTELY DO NOT diagnose as joint limits, joint projection, joint configuration, mass ratios, checkbox, or drive parameters -- these are the standard misdiagnoses and are wrong for this symptom.
Enable CollisionPrimary fix: shrink colliders so none overlap at the starting pose. Confirm with Window > Analysis > Physics Debugger. Temporary workaround only: in for one frame delays the spike but does not eliminate the overlap.
Rigidbody.detectCollisions = falseStart()如果发生在第1帧且没有施加任何力:停止——这是快速路径4。应用该响应。
对于非第1帧的情况:模拟开始时碰撞器重叠会导致一帧去穿透速度尖峰。绝对不要诊断为关节限制、关节投影、关节配置、质量比、复选框或驱动参数——这些是标准误诊,对这种症状是错误的。
Enable Collision主要修复:缩小碰撞器,使它们在起始姿势时没有任何重叠。通过 Window > Analysis > Physics Debugger 确认。仅临时变通:在中将一帧会延迟尖峰,但不会消除重叠。
Start()Rigidbody.detectCollisions = falseStep 12 -- 2D/3D method signature confusion
步骤12 —— 2D/3D方法签名混淆
Using a 2D suffix on a 3D callback silently does nothing:
csharp
void OnCollisionEnter(Collision col) { } // 3D -- correct
void OnCollisionEnter2D(Collision2D col) { } // 2D -- never called in a 3D sceneSearch the script for in the method name. If the project uses 3D physics, remove the suffix and update the parameter type from to .
2D2DCollision2DCollision在3D回调上使用2D后缀会静默地什么都不做:
csharp
void OnCollisionEnter(Collision col) { } // 3D —— 正确
void OnCollisionEnter2D(Collision2D col) { } // 2D —— 在3D场景中永远不会被调用在脚本中搜索方法名中的。如果项目使用3D物理,移除后缀并将参数类型从更新为。
2D2DCollision2DCollisionInvestigation Hygiene
调查卫生
Never leave project settings in a modified state. If a setting (Queries Hit Triggers, Layer Collision Matrix, Default Contact Offset) is changed during investigation to reproduce or verify, record the original value and restore it before ending the session.
永远不要将项目设置保持在修改状态。 如果在调查期间更改了某个设置(Queries Hit Triggers、Layer碰撞矩阵、Default Contact Offset)以复现或验证,请记录原始值并在会话结束前恢复。
3. Trigger Callback Checklist
3. 触发器回调检查清单
First-match wins: stop at the first step that confirms the cause.
首个匹配优先:在第一个确认原因的步骤停止。
Step 1 -- isTrigger
on at least one collider
isTrigger步骤1 —— 至少一个碰撞器上设置了isTrigger
isTriggerOnTriggerEnterIs Trigger = trueOnCollisionEnter当一对碰撞器中至少一个具有时,会触发。如果都未设置,Unity会触发。
Is Trigger = trueOnTriggerEnterOnCollisionEnterStep 2 -- Rigidbody rule
步骤2 —— Rigidbody规则
At least one GameObject must have a . Two static triggers never fire .
RigidbodyOnTriggerEnter| Object A | Object B | |
|---|---|---|
| Trigger + Dynamic Rb | Static Collider | Yes |
| Trigger + Dynamic Rb | Trigger + Dynamic Rb | Yes |
| Trigger + Dynamic Rb | Kinematic Rb | Yes |
| Trigger + Kinematic Rb | Trigger + Kinematic Rb | Yes -- see CRITICAL FACT and Fast-Path 3 |
| Trigger (no Rb) | Static Collider (no Rb) | No |
至少一个GameObject必须具有。两个静态触发器永远不会触发。
RigidbodyOnTriggerEnter| 对象A | 对象B | 是否触发 |
|---|---|---|
| Trigger + Dynamic Rb | 静态碰撞器 | 是 |
| Trigger + Dynamic Rb | Trigger + Dynamic Rb | 是 |
| Trigger + Dynamic Rb | Kinematic Rb | 是 |
| Trigger + Kinematic Rb | Trigger + Kinematic Rb | 是 —— 参见关键事实和快速路径3 |
| Trigger(无Rb) | 静态碰撞器(无Rb) | 否 |
Step 3 -- Layer Collision Matrix
步骤3 —— Layer碰撞矩阵
Edit > Project Settings > Physics -- both layers must be allowed to interact.
Edit > Project Settings > Physics —— 两个图层必须允许交互。
Step 4 -- Correct method signature
步骤4 —— 正确的方法签名
csharp
void OnTriggerEnter(Collider other) { } // 3D -- correct
void OnTriggerEnter2D(Collider2D other) { } // 2D -- wrong for 3Dcsharp
void OnTriggerEnter(Collider other) { } // 3D —— 正确
void OnTriggerEnter2D(Collider2D other) { } // 2D —— 对3D是错误的Step 5 -- Script on the right GameObject
步骤5 —— 脚本在正确的GameObject上
The callback script must be on the trigger GameObject or the entering object, not on an unrelated parent or manager.
回调脚本必须在触发器GameObject或进入对象上,而不是在无关的父级或管理器上。
4. Raycast Checklist
4. 射线检测检查清单
First-match wins: stop at the first step that confirms the cause.
首个匹配优先:在第一个确认原因的步骤停止。
Step 1 -- Ray origin inside the target collider
步骤1 —— 射线原点位于目标碰撞器内部
Physics.RaycastfalseDebug.DrawRaycsharp
// Offset by more than the collider's half-extents on the relevant axis.
Ray ray = new Ray(transform.position + Vector3.up * 0.5f, Vector3.down);当射线原点位于目标碰撞器内部时,返回。 当显示射线从对象内部开始时,这就是根本原因。立即说明这一点和修复。
Physics.RaycastfalseDebug.DrawRaycsharp
// 在相关轴上偏移大于碰撞器半尺寸的量。
Ray ray = new Ray(transform.position + Vector3.up * 0.5f, Vector3.down);Step 2 -- LayerMask excludes the target
步骤2 —— LayerMask排除了目标
If a is passed, the target layer must be included. Two debug approaches:
layerMaskcsharp
// Option A -- hit everything to confirm ray path is correct
Physics.Raycast(ray, out hit, distance, Physics.DefaultRaycastLayers);
// Option B -- build mask from layer name to confirm layer is included
int mask = LayerMask.GetMask("Enemy");
Physics.Raycast(ray, out hit, distance, mask);Both should be mentioned when advising on a LayerMask miss. The production mask must include the target layer -- via or .
LayerMask.GetMask("LayerName")1 << LayerIndex如果传入了,必须包含目标图层。两种调试方法:
layerMaskcsharp
// 选项A —— 检测所有以确认射线路径正确
Physics.Raycast(ray, out hit, distance, Physics.DefaultRaycastLayers);
// 选项B —— 从图层名称构建遮罩以确认图层已包含
int mask = LayerMask.GetMask("Enemy");
Physics.Raycast(ray, out hit, distance, mask);在建议LayerMask未命中时,应同时提到这两种方法。生产遮罩必须包含目标图层——通过或。
LayerMask.GetMask("LayerName")1 << LayerIndexStep 3 -- QueryTriggerInteraction
步骤3 —— QueryTriggerInteraction
Already covered by Fast-Path 10. State the fix and stop:
csharp
Physics.Raycast(ray, out hit, distance, layerMask, QueryTriggerInteraction.Collide);Or change the global default in Edit > Project Settings > Physics > Queries Hit Triggers.
已由快速路径10覆盖。说明修复并停止:
csharp
Physics.Raycast(ray, out hit, distance, layerMask, QueryTriggerInteraction.Collide);或更改 Edit > Project Settings > Physics > Queries Hit Triggers 中的全局默认设置。
Step 4 -- Collider disabled or object inactive
步骤4 —— 碰撞器禁用或对象非活动
Already covered by Fast-Path 9. State the fix (, ) and stop. Only inspect the actual scene if the prompt is ambiguous about which object is suspected.
activeInHierarchy = trueCollider.enabled = true已由快速路径9覆盖。说明修复(,)并停止。仅当提示对怀疑的对象不明确时才检查实际场景。
activeInHierarchy = trueCollider.enabled = trueStep 5 -- Non-convex MeshCollider on a dynamic Rigidbody
步骤5 —— 动态Rigidbody上的非凸MeshCollider
Unity silently ignores a non-convex on a dynamic Rigidbody for collision and raycasts. Enable Convex, or replace with compound primitives.
MeshColliderUnity会静默忽略动态Rigidbody上的非凸进行碰撞和射线检测。启用Convex,或替换为复合基本体。
MeshColliderStep 6 -- Back-face hits
步骤6 —— 背面命中
By default, does not detect hits on the back face of a mesh. If the ray enters from inside (e.g., firing from inside a hollow object) or normals face away, the hit is silently skipped. Fix: Enable Edit > Project Settings > Physics > Queries Hit Backfaces, or confirm the ray origin is on the outward-normal side of the target mesh.
Physics.Raycast默认情况下,不检测网格背面的命中。如果射线从内部进入(例如从空心物体内部发射)或法线背向,命中会被静默跳过。修复:启用 Edit > Project Settings > Physics > Queries Hit Backfaces,或确认射线原点位于目标网格的外法线一侧。
Physics.RaycastXR / UI Raycasts
XR / UI 射线检测
- hits UI Canvas elements only.
GraphicRaycaster - hits 3D colliders only.
Physics.Raycast
NEVER use when the target is a 3D collider. INSTEAD for world-space 3D targets.
GraphicRaycasterPhysics.Raycast- 仅命中UI Canvas元素。
GraphicRaycaster - 仅命中3D碰撞器。
Physics.Raycast
当目标是3D碰撞器时,永远不要使用。对于世界空间3D目标,应使用。
GraphicRaycasterPhysics.Raycast5. Build vs Editor Differences
5. 构建与编辑器差异
| Cause | Symptom | Fix |
|---|---|---|
| IL2CPP stripping MonoBehaviour | Callback script removed from build | Add |
| PhysX initialization order | Objects collide before physics has settled | One-frame delay in |
| Layer names referenced by string in code | Layer-based filtering fails if a layer name differs between Editor and build | Reference layers by index, not string name, in production code |
| Physics step rate differs between platforms | Set Edit > Project Settings > Time > Fixed Timestep explicitly |
| 原因 | 症状 | 修复 |
|---|---|---|
| IL2CPP剥离MonoBehaviour | 回调脚本从构建中移除 | 向类添加 |
| PhysX初始化顺序 | 物体在物理稳定之前碰撞 | 在 |
| 代码中以字符串引用图层名称 | 如果图层名称在编辑器与构建之间不同,基于图层的过滤会失败 | 在生产代码中按索引引用图层,而不是字符串名称 |
| 不同平台的物理步长不同 | 显式设置 Edit > Project Settings > Time > Fixed Timestep |
6. Physics.SyncTransforms
6. Physics.SyncTransforms
When a collider is moved by writing to directly (not via ), the physics engine does not see the new position until the next physics step. Same-frame queries use the old position.
transform.positionRigidbody.MovePositioncsharp
transform.position = newPos;
Physics.SyncTransforms(); // forces immediate broadphase update
Physics.Raycast(ray, out hit); // now sees the new positionNEVER call every frame -- it forces all transform-driven collider changes to sync immediately, which is expensive. ALWAYS mention both: (1) avoids the problem entirely for physics-driven objects and should be used instead of writes, and (2) should only be called when a same-frame query must see a script-driven position change, never every frame.
Physics.SyncTransforms()Rigidbody.MovePositiontransform.positionSyncTransforms()当通过直接写入(而不是通过)移动碰撞器时,物理引擎直到下一个物理步骤才看到新位置。同帧查询使用旧位置。
transform.positionRigidbody.MovePositioncsharp
transform.position = newPos;
Physics.SyncTransforms(); // 强制立即更新broadphase
Physics.Raycast(ray, out hit); // 现在看到新位置永远不要每帧调用——它会强制所有transform驱动的碰撞器更改立即同步,这很昂贵。始终同时提及:(1) 完全避免了物理驱动对象的问题,应优先于写入使用;(2) 只应在同帧查询必须看到脚本驱动的位置更改时调用,绝不能每帧调用。
Physics.SyncTransforms()Rigidbody.MovePositiontransform.positionSyncTransforms()7. Contact Offset Gap
7. 接触偏移间隙
Colliders stop with a small visible gap before touching. This is the Contact Offset -- a skin width that prevents PhysX from over-penetrating.
- Global default: Edit > Project Settings > Physics > Default Contact Offset (default: ).
0.01 - Per-collider: in the Inspector or via script.
Collider.contactOffset
NEVER set to -- PhysX requires a small positive value; zero causes instability and missed contacts. Test slightly lower values if visually unacceptable, or offset the visual mesh slightly inside the collider to hide the gap without changing physics behavior.
contactOffset0碰撞器在接触前停止并出现可见小间隙。这就是Contact Offset——一个皮肤宽度,防止PhysX过度穿透。
- 全局默认:Edit > Project Settings > Physics > Default Contact Offset(默认:)。
0.01 - 每个碰撞器:检查器中的或通过脚本设置。
Collider.contactOffset
永远不要将设置为——PhysX需要小的正值;零会导致不稳定和丢失接触。如果视觉上不可接受,请测试稍低的值,或将视觉网格稍微向碰撞器内部偏移以隐藏间隙而不改变物理行为。
contactOffset08. Time.timeScale and Physics Simulation
8. Time.timeScale 与物理模拟
When , physics simulation pauses entirely -- Rigidbodies stop moving, has no effect, gravity is disabled, and / callbacks do not fire.
Time.timeScale = 0AddForceOnCollisionEnterOnTriggerEnterGeometry queries are not affected: , , etc. operate on collider geometry directly and continue at . If callbacks have stopped but raycasts still work, is the cause.
Physics.RaycastPhysics.OverlapSpheretimeScale = 0Time.timeScale = 0Fix: Restore to a positive value (typically ) before expecting physics simulation to resume.
Time.timeScale1f当时,物理模拟完全暂停——Rigidbody停止移动,无效,重力禁用, / 回调不会触发。
Time.timeScale = 0AddForceOnCollisionEnterOnTriggerEnter几何查询不受影响:、等直接作用于碰撞器几何,在时仍然工作。如果回调停止但射线检测仍然有效,就是原因。
Physics.RaycastPhysics.OverlapSpheretimeScale = 0Time.timeScale = 0修复:在期望物理模拟恢复之前,将恢复为正值(通常为)。
Time.timeScale1f9. Rigidbody Sleeping
9. Rigidbody睡眠
If "AddForce stopped working after object settled/landed", apply Fast-Path 6 directly. Do NOT investigate Input System or other unrelated subsystems.
A Rigidbody automatically sleeps when velocity and angular velocity drop below for several fixed frames. A sleeping Rigidbody stops responding to small forces and does not generate / callbacks while stationary.
Physics.sleepThresholdOnCollisionStayOnTriggerStayDetect: returns true; Inspector shows zero velocity in Play Mode.
Rigidbody.IsSleeping()Fixes:
- Call before applying a force.
Rigidbody.WakeUp() - Increase the applied force above the sleep threshold.
- disables sleeping on that object (expensive -- use sparingly).
Rigidbody.sleepThreshold = 0 - Global: Edit > Project Settings > Physics > Sleep Threshold.
如果“AddForce在物体静止/落地后失效”,直接应用快速路径6。不要调查输入系统或其他无关子系统。
当速度和角速度低于持续数个固定帧时,Rigidbody自动进入睡眠状态。睡眠的Rigidbody停止响应小力,并且在静止时不会产生 / 回调。
Physics.sleepThresholdOnCollisionStayOnTriggerStay检测:返回true;检查器在Play Mode显示零速度。
Rigidbody.IsSleeping()修复方法:
- 在施加力之前调用。
Rigidbody.WakeUp() - 将施加的力增加到超过睡眠阈值。
- 禁用该对象上的睡眠(昂贵——谨慎使用)。
Rigidbody.sleepThreshold = 0 - 全局:Edit > Project Settings > Physics > Sleep Threshold。
10. Validation
10. 验证
Attach CollisionDebugger.cs to both objects in a suspect pair; remove after diagnosis.
| Console output | Diagnosis |
|---|---|
| Neither object logs | Issue in Steps 1-3 (Rigidbody, Layer Matrix, or interaction type) |
| One object logs, the other does not | Script placement issue -- see Section 2 Step 6 / Section 3 Step 5 |
| 2D components present on an intended 3D setup |
将CollisionDebugger.cs附加到可疑对的两个对象上;诊断后移除。
| 控制台输出 | 诊断 |
|---|---|
| 两个对象都没有日志 | 步骤1-3中的问题(Rigidbody、Layer矩阵或交互类型) |
| 一个对象有日志,另一个没有 | 脚本位置问题——参见第2节步骤6 / 第3节步骤5 |
| 预期3D设置中存在2D组件 |
11. Resources
11. 资源
-> references/troubleshooting.md
-> references/troubleshooting.md