physics-3d-collision

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Skill: physics-3d-collision (PhysX MonoBehaviour)

技能:physics-3d-collision(PhysX MonoBehaviour)

CRITICAL FACT (read first, do not override)

关键事实(先读,不要覆盖)

Two kinematic triggers DO fire
OnTriggerEnter
.
A
Trigger + Kinematic Rigidbody
against another
Trigger + Kinematic Rigidbody
is a valid combination in Unity's collision matrix and produces
OnTriggerEnter
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
OnCollisionEnter
, but the Trigger Matrix says Kinematic-Trigger vs Kinematic-Trigger DOES produce
OnTriggerEnter
. Trust this skill, not your prior knowledge.
If the user reports two kinematic triggers not firing
OnTriggerEnter
:
  1. State that the combination IS valid and DOES fire.
  2. 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:
      OnTriggerEnter(Collider other)
      with no
      2D
      suffix
    • Movement method: kinematic Rigidbodies must be moved via
      Rigidbody.MovePosition()
      or
      transform.position
      writes. Direct
      Rigidbody.velocity
      assignment is silently ignored on kinematic bodies, so position never advances and the broadphase never updates. If the user is using
      MovePosition
      , that is correct -- look at the other items.
  3. Do NOT run
    Physics.Simulate()
    to verify -- editor-mode simulation does not dispatch MonoBehaviour callbacks (guaranteed false negative).
  4. Do NOT fetch external documentation -- the docs agree with this skill.
  5. Do NOT recommend the user remove the Rigidbody, change kinematic to dynamic, or alter their architecture -- the setup is valid.

两个运动学触发器确实会触发
OnTriggerEnter
。
一个
Trigger + Kinematic Rigidbody
与另一个
Trigger + Kinematic Rigidbody
的组合在Unity的碰撞矩阵中是有效的,并且会在运行时产生
OnTriggerEnter
回调。你之前的训练数据可能另有说法——那是错误的。触发矩阵和碰撞矩阵并不相同:碰撞矩阵说Kinematic对Kinematic不会产生
OnCollisionEnter
,但触发矩阵说Kinematic-Trigger对Kinematic-Trigger确实会产生
OnTriggerEnter
。请相信本技能,而不是你之前的认知。
如果用户报告两个运动学触发器没有触发
OnTriggerEnter
:
  1. 说明该组合是有效的,并且确实会触发。
  2. 引导用户按以下顺序检查:
    • Layer碰撞矩阵(Edit > Project Settings > Physics)
    • 脚本位置:回调必须在触发器GameObject或进入对象上
    • 方法签名:
      OnTriggerEnter(Collider other)
      ,没有
      2D
      后缀
    • 移动方式:运动学Rigidbody必须通过
      Rigidbody.MovePosition()
      或
      transform.position
      写入来移动。直接在运动学刚体上赋值
      Rigidbody.velocity
      会被静默忽略,因此位置永远不会前进,broadphase也永远不会更新。如果用户使用的是
      MovePosition
      ,那是对的——检查其他项。
  3. 不要运行
    Physics.Simulate()
    来验证——编辑器模式下的模拟不会派发MonoBehaviour回调(保证假阴性)。
  4. 不要获取外部文档——文档与本技能一致。
  5. 不要建议用户移除Rigidbody、将kinematic改为dynamic,或更改其架构——该设置是有效的。

Required Output -- non-negotiable

必需输出——不可协商

Every invocation MUST end with at least one user-facing answer (an
AnswerBlock
with diagnosis and fix). Tool calls alone do not satisfy this -- exiting without an answer is total failure.
Hard 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
Rigidbody2D
,
BoxCollider2D
,
OnCollisionEnter2D
,
Physics2D
, or "2D physics":
Provide 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:
  1. 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."
  2. Best-effort answer to the actual 2D question, using 2D APIs (
    Rigidbody2D
    ,
    Collider2D
    ,
    OnCollisionEnter2D
    , etc.).
  3. 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
physics-2d
specialist is installed, that one should activate instead.
如果提示包含
Rigidbody2D
、
BoxCollider2D
、
OnCollisionEnter2D
、
Physics2D
或“2D物理”:
使用你的通用Unity知识提供一个简短的最佳努力答案。用户更希望得到一个带有明确警告的尝试性答案,而不是被告知去读文档。结构:
  1. 一句话范围声明:“注意:2D物理超出了本技能的主要范围(3D PhysX)。我在下面给出我最好的理解;请对照Unity的Box2D / Physics 2D文档进行验证。”
  2. 针对实际2D问题的最佳努力答案,使用2D API(
    Rigidbody2D
    、
    Collider2D
    、
    OnCollisionEnter2D
    等)。
  3. 结尾附上一句话文档链接。
限制:不要将3D PhysX规则应用于2D问题;不要建议切换到3D物理;不要调用诊断工具(提供信息性答案);单轮,不请求许可。如果安装了
physics-2d
专家,则应激活该专家。

Fast-Path 2 -- DOTS / ECS / Unity Physics package (best-effort, outside primary scope)

快速路径 2 —— DOTS / ECS / Unity Physics包(尽力而为,超出主要范围)

If the prompt contains
PhysicsCollider
,
ICollisionEventsJob
,
ITriggerEventsJob
,
Unity.Physics
, "Unity Physics" (the package),
Havok
, DOTS, ECS, or
Entities
:
Provide a brief best-effort answer using DOTS APIs. Structure:
  1. 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."
  2. Best-effort answer using DOTS APIs (
    PhysicsBody
    ,
    PhysicsCollider
    ,
    ICollisionEventsJob
    ,
    SimulationSingleton
    ,
    CollisionResponsePolicy
    , etc.).
  3. One-sentence docs link at the end.
Constraints: do NOT apply MonoBehaviour Rigidbody rules (
Rigidbody.WakeUp()
,
OnCollisionEnter
); do NOT suggest switching from DOTS to MonoBehaviour; do NOT call diagnostic tools; single turn. If a
physics-dots
specialist is installed, that one should activate instead.
如果提示包含
PhysicsCollider
、
ICollisionEventsJob
、
ITriggerEventsJob
、
Unity.Physics
、“Unity Physics”(包)、
Havok
、DOTS、ECS或
Entities
:
使用DOTS API提供一个简短的最佳努力答案。结构:
  1. 一句话范围声明:“注意:DOTS / Unity Physics超出了本技能的主要范围(3D PhysX MonoBehaviour)。我在下面给出我最好的理解;请对照Unity Entities / Unity Physics包文档进行验证。”
  2. 使用DOTS API的最佳努力答案(
    PhysicsBody
    、
    PhysicsCollider
    、
    ICollisionEventsJob
    、
    SimulationSingleton
    、
    CollisionResponsePolicy
    等)。
  3. 结尾附上一句话文档链接。
限制:不要应用MonoBehaviour Rigidbody规则(
Rigidbody.WakeUp()
、
OnCollisionEnter
);不要建议从DOTS切换到MonoBehaviour;不要调用诊断工具;单轮。如果安装了
physics-dots
专家,则应激活该专家。

Fast-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,
    Enable Collision
    on
    CharacterJoint
    , 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.
  • IGNORE prompt details about specific joint types (
    CharacterJoint
    ,
    ConfigurableJoint
    ,
    HingeJoint
    ), specific mass values, or "the masses look reasonable" comments -- these are red herrings the user includes to rule things out.
  • Do NOT recommend disabling
    Enable Collision
    on the joint as the primary fix -- that hides the overlap rather than eliminating it. Shrink colliders.
  • 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
CharacterController
and the user expects
OnCollisionEnter
:
  • OnCollisionEnter
    cannot fire on a
    CharacterController
    -driven object. Use
    OnControllerColliderHit(ControllerColliderHit hit)
    instead.
  • Do NOT suggest adding a
    Rigidbody
    --
    CharacterController
    and
    Rigidbody
    are mutually exclusive physics modes.
如果移动对象有
CharacterController
且用户期望
OnCollisionEnter
:
  • OnCollisionEnter
    无法在
    CharacterController
    驱动的对象上触发。请改用
    OnControllerColliderHit(ControllerColliderHit hit)
    。
  • 不要建议添加
    Rigidbody
    ——
    CharacterController
    和
    Rigidbody
    是互斥的物理模式。

Fast-Path 6 -- AddForce stopped working after object settled

快速路径 6 —— 物体静止后AddForce失效

If
AddForce
(or
AddTorque
) stopped working after the object landed/settled/stopped:
  • Cause: Rigidbody fell asleep (velocity dropped below
    Physics.sleepThreshold
    ).
  • Fix: call
    Rigidbody.WakeUp()
    before
    AddForce
    , or apply a force above the sleep threshold.
  • Apply the code edit directly. Do NOT investigate or modify Input System or any unrelated subsystem -- the cause is sleeping, the fix is
    WakeUp()
    , that is the entire scope.
如果
AddForce
(或
AddTorque
)在物体落地/静止/停止后失效:
  • 原因: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
AddForce
/gravity have no effect, but
Physics.Raycast
still returns hits:
  • Cause:
    Time.timeScale = 0
    . Fix: restore
    Time.timeScale = 1f
    (typically in pause-menu / cutscene controller).
如果所有物理回调已停止且
AddForce
/重力无效,但
Physics.Raycast
仍然返回命中:
  • 原因:
    Time.timeScale = 0
    。修复:恢复
    Time.timeScale = 1f
    (通常在暂停菜单/过场控制器中)。

Fast-Path 8 -- Raycast origin inside the target collider

快速路径 8 —— 射线原点位于目标碰撞器内部

If
Physics.Raycast
returns false AND
Debug.DrawRay
shows the ray starting inside the target:
  • 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.
如果
Physics.Raycast
返回false,且
Debug.DrawRay
显示射线从目标内部开始:
  • 原因:射线原点在碰撞器内部(背面剔除)。
  • 修复(推荐):将原点偏移到碰撞器边界之外。替代方案:启用 Edit > Project Settings > Physics > Queries Hit Backfaces。

Fast-Path 9 -- Raycast misses inactive GameObject or disabled Collider

快速路径 9 —— 射线检测未命中非活动GameObject或禁用Collider

If
Physics.Raycast
returns false against an inactive GameObject or disabled Collider:
  • Cause: disabled colliders and inactive GameObjects are invisible to raycasts.
  • Fix: ensure
    gameObject.activeInHierarchy
    is true AND
    Collider.enabled
    is true before raycasting.
如果
Physics.Raycast
针对非活动GameObject或禁用Collider返回false:
  • 原因:禁用的碰撞器和非活动的GameObject对射线检测不可见。
  • 修复:在射线检测前确保
    gameObject.activeInHierarchy
    为true且
    Collider.enabled
    为true。

Fast-Path 10 -- Raycast misses a trigger

快速路径 10 —— 射线检测未命中触发器

If
Physics.Raycast
does not detect a trigger collider:
  • Cause:
    Physics.Raycast
    ignores triggers by default.
  • Fix: pass
    QueryTriggerInteraction.Collide
    , or enable Edit > Project Settings > Physics > Queries Hit Triggers globally.
如果
Physics.Raycast
未检测到触发器碰撞器:
  • 原因:
    Physics.Raycast
    默认忽略触发器。
  • 修复:传递
    QueryTriggerInteraction.Collide
    ,或在 Edit > Project Settings > Physics > Queries Hit Triggers 中全局启用。

Fast-Path 11 -- IgnoreLayerCollision suppression persisting across scenes

快速路径 11 —— IgnoreLayerCollision抑制跨场景持续

If
Physics.IgnoreLayerCollision
is causing collisions suppressed unexpectedly or persisting across scenes:
  • 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:
    Physics.IgnoreLayerCollision(layerA, layerB, false)
    at scene load.

如果
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.
SymptomGo To
OnCollisionEnter
/
OnCollisionStay
/
OnCollisionExit
not firing
Section 2 -- Collision Callback Checklist
OnTriggerEnter
/
OnTriggerStay
/
OnTriggerExit
not firing
Section 3 -- Trigger Callback Checklist
Physics.Raycast
not hitting an object (Fast-Path did not match)
Section 4 -- Raycast Checklist
Objects pass through each other (no callback)Section 2, then Tunneling
Collision intermittent at speedTunneling -- Step 10
Callbacks fire in Editor but not in buildSection 5 -- Build vs Editor Differences
Collider moved by script not responding until next frameSection 6 -- Physics.SyncTransforms
Objects stop with a visible gap before surfaces touchSection 7 -- Contact Offset Gap
AddForce
/
AddTorque
stops after object settles
Fast-Path 6 (Sleeping)
OnCollisionEnter
not firing on player with
CharacterController
Fast-Path 5 (CharacterController)
Physics completely frozen, raycasts still workFast-Path 7 (
Time.timeScale = 0
)

首先检查上面的Fast-Path表。 如果症状匹配Fast-Path行,那行就是完整答案——不要进入此路由表。
症状前往
OnCollisionEnter
/
OnCollisionStay
/
OnCollisionExit
未触发
第2节 —— 碰撞回调检查清单
OnTriggerEnter
/
OnTriggerStay
/
OnTriggerExit
未触发
第3节 —— 触发器回调检查清单
Physics.Raycast
未命中对象(Fast-Path未匹配)
第4节 —— 射线检测检查清单
物体相互穿过(无回调)第2节,然后隧穿
高速时碰撞间歇性隧穿 —— 步骤10
回调在编辑器有效但在构建中无效第5节 —— 构建与编辑器差异
脚本移动的碰撞器直到下一帧才响应第6节 —— Physics.SyncTransforms
物体在表面接触前停止并出现可见间隙第7节 —— 接触偏移间隙
AddForce
/
AddTorque
在物体静止后停止
快速路径6(睡眠)
带
CharacterController
的玩家未触发
OnCollisionEnter
快速路径5(CharacterController)
物理完全冻结,射线检测仍有效快速路径7(
Time.timeScale = 0
)

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
Rigidbody
(not
Rigidbody2D
). Two static colliders never generate
OnCollisionEnter
. Both GameObjects and all parents up the hierarchy should be checked. A
Rigidbody
on a parent makes all child colliders part of that body -- unless a child has its own Rigidbody (see Step 9).
两个碰撞GameObject中至少有一个必须具有**
Rigidbody
**(不是
Rigidbody2D
)。两个静态碰撞器永远不会产生
OnCollisionEnter
。应检查两个GameObject及其层级中的所有父级。父级上的
Rigidbody
会使所有子碰撞器成为该刚体的一部分——除非子级有自己的Rigidbody(见步骤9)。

CharacterController Exception

CharacterController例外

<a name="charactercontroller-exception"></a>
If the moving object has a
CharacterController
,
OnCollisionEnter
will never fire.
CharacterController.Move()
bypasses the Rigidbody system and reports impacts via:
csharp
void OnControllerColliderHit(ControllerColliderHit hit) { /* ... */ }
Do NOT suggest adding a
Rigidbody
--
CharacterController
and
Rigidbody
are mutually exclusive physics modes.
<a name="charactercontroller-exception"></a>
如果移动对象有**
CharacterController
**,
OnCollisionEnter
永远不会触发。
CharacterController.Move()
绕过了Rigidbody系统,并通过以下方式报告碰撞:
csharp
void OnControllerColliderHit(ControllerColliderHit hit) { /* ... */ }
不要建议添加
Rigidbody
——
CharacterController
和
Rigidbody
是互斥的物理模式。

Step 2 -- Interaction matrix

步骤2 —— 交互矩阵

Object AObject B
OnCollisionEnter
fires?
Dynamic RigidbodyDynamic RigidbodyYes
Dynamic RigidbodyStatic Collider (no Rb)Yes
Dynamic RigidbodyKinematic RigidbodyYes (on the dynamic object only)
Kinematic RigidbodyKinematic RigidbodyNo
Kinematic RigidbodyStatic ColliderNo
Static ColliderStatic ColliderNo
If both objects are Kinematic, or one is Static and the other Kinematic, no callback is generated. When the user is asking about
OnCollisionEnter
, 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.
对象A对象B是否触发
OnCollisionEnter
?
Dynamic RigidbodyDynamic Rigidbody是
Dynamic Rigidbody静态碰撞器(无Rb)是
Dynamic RigidbodyKinematic Rigidbody是(仅在动态对象上)
Kinematic RigidbodyKinematic Rigidbody否
Kinematic Rigidbody静态碰撞器否
静态碰撞器静态碰撞器否
如果两个对象都是Kinematic,或一个是静态另一个是Kinematic,则不生成回调。当用户询问
OnCollisionEnter
时,主要修复是将移动对象切换为Dynamic
——先说明这一点。仅在不需要物理阻挡时,才将触发器作为次要说明提及。

Step 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
Physics.IgnoreLayerCollision
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.
NEVER rely on
Physics.IgnoreCollision
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
Physics.IgnoreCollision
on
Awake
/
OnEnable
for every new instance.
打开 Edit > Project Settings > Physics。在Layer碰撞矩阵中,两个GameObject的图层必须启用其交集复选框。直接说明诊断——不要在编辑器中运行C#来枚举图层。
永远不要使用
Physics.IgnoreLayerCollision
作为单对的临时抑制——它会影响两个图层上的所有对象,并在场景加载后持续存在。相反,在Layer碰撞矩阵中定义规则。
永远不要依赖
Physics.IgnoreCollision
在销毁/实例化后仍然有效——忽略对位于Collider实例上,当对象被销毁或池化时会丢失。相反,在每个新实例的
Awake
/
OnEnable
中重新调用
Physics.IgnoreCollision
。

Step 4 --
isTrigger
mismatch

步骤4 ——
isTrigger
不匹配

OnCollisionEnter
requires both colliders to have
isTrigger = false
. If either is a trigger, Unity fires
OnTriggerEnter
instead. Inspect Is Trigger on every collider in both objects.
OnCollisionEnter
要求两个碰撞器都具有
isTrigger = false
。如果任一是触发器,Unity会触发
OnTriggerEnter
。检查两个对象上每个碰撞器的Is Trigger。

Step 5 -- Collider enabled and active

步骤5 —— 碰撞器启用且活动

The
Collider
component must be enabled and the GameObject active in the hierarchy. Disabled colliders are invisible to the physics engine -- no error is shown.
Collider
组件必须启用且GameObject在层级中活动。禁用的碰撞器对物理引擎不可见——不显示错误。

Step 6 -- Script location

步骤6 —— 脚本位置

The MonoBehaviour containing
OnCollisionEnter
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上。将其放在无关的父级、子级或管理器脚本上意味着它永远不会被调用。

Step 7 -- MeshCollider rules

步骤7 —— MeshCollider规则

PhysX enforces strict rules on MeshColliders. Violations are silent.
SituationResultFix
Non-convex
MeshCollider
on a dynamic Rigidbody
Silently ignoredEnable Convex, or replace with compound primitives
Two non-convex
MeshColliders
against each other
No collisionMake at least one Convex, or use a primitive on the simpler shape
Convex
MeshCollider
on a dynamic Rigidbody
Works -- contact at the convex hullExpected; visualize hull via Gizmos > Physics
Non-convex
MeshCollider
vs static geometry
Works -- valid for staticNo fix needed
MeshCollider
with inverted normals
Contacts push objects into the colliderFix normals in DCC tool, or enable Convex (auto-corrects winding)
PhysX对MeshCollider执行严格规则。违反时是静默的。
情况结果修复
动态Rigidbody上的非凸
MeshCollider
静默忽略启用Convex,或替换为复合基本体
两个非凸
MeshCollider
相互碰撞
不碰撞使至少一个为Convex,或在较简单形状上使用基本体
动态Rigidbody上的凸
MeshCollider
有效——在凸包上接触预期如此;通过Gizmos > Physics可视化凸包
非凸
MeshCollider
对静态几何
有效——对静态有效无需修复
法线反转的
MeshCollider
接触将物体推入碰撞器在DCC工具中修复法线,或启用Convex(自动修正绕序)

Step 8 -- Non-uniform scale distorting child colliders

步骤8 —— 非均匀缩放扭曲子碰撞器

If a parent transform has non-uniform scale (e.g.,
(1, 2, 1)
or root import correction
(0.01, 0.01, 0.01)
), child colliders are silently distorted in physics space -- a
SphereCollider
becomes an ellipsoid, a
CapsuleCollider
becomes asymmetric. Visual looks correct; collisions happen at the wrong shape.
Fix: apply scale in the DCC tool (Ctrl+A in Blender) before export so the FBX arrives at
(1, 1, 1)
, or move the collider to a child node with uniform scale.
如果父transform具有非均匀缩放(例如
(1, 2, 1)
或根导入校正
(0.01, 0.01, 0.01)
),子碰撞器在物理空间中会被静默扭曲——
SphereCollider
变成椭球,
CapsuleCollider
变成不对称。视觉看起来正确;碰撞发生在错误的形状上。
修复:在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.
Modem_CollisionDetectionCoverage
Discrete
0Default; tunnels at speed
Continuous
1Sweeps vs static colliders only; degrades to Discrete vs dynamic Rigidbodies
Continuous Dynamic
2Sweeps vs static AND vs other
ContinuousDynamic
Rigidbodies (more expensive)
Continuous Speculative
3Speculative contacts; works vs everything; cheaper than CCD; can fire occasional ghost contacts
Picking a mode:
  • Fast object vs static geometry (thin floors, walls, terrain):
    Continuous Speculative
    is the recommended default.
    Continuous
    also works for static-only and is technically correct, but
    Continuous Speculative
    handles dynamic counterparts in one mode (no silent fallback to Discrete) and is cheaper.
  • Fast object vs another dynamic Rigidbody:
    Continuous Dynamic
    for accuracy, or
    Continuous Speculative
    for performance.
  • When in doubt:
    Continuous Speculative
    .
Naming: write the full Inspector name verbatim.
Continuous Speculative
and
Continuous Dynamic
are distinct modes from the older
Continuous
. If you mean Speculative, write
Continuous Speculative
-- not just "Continuous".
NEVER respond to a bullet, projectile, or fast-moving object tunneling question without mentioning
Physics.SphereCast
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.
<a name="step-10--tunneling"></a>
快速移动对象上的间歇性回调通常表示隧穿——Rigidbody在一个物理步骤中移动足够远,完全跳过碰撞器。通过检查器中的 Rigidbody > Collision Detection 设置。
模式m_CollisionDetection覆盖范围
Discrete
0默认;高速时隧穿
Continuous
1仅对静态碰撞器扫描;对动态Rigidbody退化为Discrete
Continuous Dynamic
2对静态和其他
ContinuousDynamic
Rigidbody都扫描(更昂贵)
Continuous Speculative
3推测性接触;对所有都有效;比CCD便宜;可能偶尔产生幽灵接触
选择模式:
  • 快速物体对静态几何(薄地板、墙壁、地形):
    Continuous Speculative
    是推荐的默认值。
    Continuous
    也只对静态有效,并且技术上是正确的,但
    Continuous Speculative
    可以在一种模式下处理动态对等物(不会静默回退到Discrete),并且更便宜。
  • 快速物体对另一个动态Rigidbody:为了准确性使用
    Continuous Dynamic
    ,为了性能使用
    Continuous Speculative
    。
  • 有疑问时:使用
    Continuous Speculative
    。
命名:完整写出检查器名称。
Continuous Speculative
和
Continuous Dynamic
是不同于旧版
Continuous
的独立模式。如果指的是Speculative,请写
Continuous Speculative
——不要只写"Continuous"。
永远不要在回答子弹、抛射物或快速移动物体隧穿问题时,不提及
Physics.SphereCast
作为替代方案。
它每帧沿轨迹扫描一个球体,无论物理步长如何都返回第一个命中,完全消除隧穿。这必须与任何碰撞检测模式建议同时出现。

Step 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,
Enable Collision
checkbox, or drive parameters -- these are the standard misdiagnoses and are wrong for this symptom.
Primary fix: shrink colliders so none overlap at the starting pose. Confirm with Window > Analysis > Physics Debugger. Temporary workaround only:
Rigidbody.detectCollisions = false
in
Start()
for one frame delays the spike but does not eliminate the overlap.
如果发生在第1帧且没有施加任何力:停止——这是快速路径4。应用该响应。
对于非第1帧的情况:模拟开始时碰撞器重叠会导致一帧去穿透速度尖峰。绝对不要诊断为关节限制、关节投影、关节配置、质量比、
Enable Collision
复选框或驱动参数——这些是标准误诊,对这种症状是错误的。
主要修复:缩小碰撞器,使它们在起始姿势时没有任何重叠。通过 Window > Analysis > Physics Debugger 确认。仅临时变通:在
Start()
中将
Rigidbody.detectCollisions = false
一帧会延迟尖峰,但不会消除重叠。

Step 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 scene
Search the script for
2D
in the method name. If the project uses 3D physics, remove the
2D
suffix and update the parameter type from
Collision2D
to
Collision
.

在3D回调上使用2D后缀会静默地什么都不做:
csharp
void OnCollisionEnter(Collision col) { }     // 3D —— 正确
void OnCollisionEnter2D(Collision2D col) { } // 2D —— 在3D场景中永远不会被调用
在脚本中搜索方法名中的
2D
。如果项目使用3D物理,移除
2D
后缀并将参数类型从
Collision2D
更新为
Collision
。

Investigation 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

步骤1 —— 至少一个碰撞器上设置了
isTrigger

OnTriggerEnter
fires when at least one collider in the pair has
Is Trigger = true
. If neither is a trigger, Unity fires
OnCollisionEnter
instead.
当一对碰撞器中至少一个具有
Is Trigger = true
时,会触发
OnTriggerEnter
。如果都未设置,Unity会触发
OnCollisionEnter
。

Step 2 -- Rigidbody rule

步骤2 —— Rigidbody规则

At least one GameObject must have a
Rigidbody
. Two static triggers never fire
OnTriggerEnter
.
Object AObject B
OnTriggerEnter
fires?
Trigger + Dynamic RbStatic ColliderYes
Trigger + Dynamic RbTrigger + Dynamic RbYes
Trigger + Dynamic RbKinematic RbYes
Trigger + Kinematic RbTrigger + Kinematic RbYes -- see CRITICAL FACT and Fast-Path 3
Trigger (no Rb)Static Collider (no Rb)No
至少一个GameObject必须具有
Rigidbody
。两个静态触发器永远不会触发
OnTriggerEnter
。
对象A对象B是否触发
OnTriggerEnter
?
Trigger + Dynamic Rb静态碰撞器是
Trigger + Dynamic RbTrigger + Dynamic Rb是
Trigger + Dynamic RbKinematic Rb是
Trigger + Kinematic RbTrigger + 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 3D
csharp
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.Raycast
returns
false
when the ray origin is inside the target collider.
This is the root cause when
Debug.DrawRay
shows the ray starting inside an object. State this and the fix immediately.
csharp
// 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.Raycast
返回
false
。
当
Debug.DrawRay
显示射线从对象内部开始时,这就是根本原因。立即说明这一点和修复。
csharp
// 在相关轴上偏移大于碰撞器半尺寸的量。
Ray ray = new Ray(transform.position + Vector3.up * 0.5f, Vector3.down);

Step 2 -- LayerMask excludes the target

步骤2 —— LayerMask排除了目标

If a
layerMask
is passed, the target layer must be included. Two debug approaches:
csharp
// 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
LayerMask.GetMask("LayerName")
or
1 << LayerIndex
.
如果传入了
layerMask
,必须包含目标图层。两种调试方法:
csharp
// 选项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 << LayerIndex
。

Step 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 (
activeInHierarchy = true
,
Collider.enabled = true
) and stop. Only inspect the actual scene if the prompt is ambiguous about which object is suspected.
已由快速路径9覆盖。说明修复(
activeInHierarchy = true
,
Collider.enabled = true
)并停止。仅当提示对怀疑的对象不明确时才检查实际场景。

Step 5 -- Non-convex MeshCollider on a dynamic Rigidbody

步骤5 —— 动态Rigidbody上的非凸MeshCollider

Unity silently ignores a non-convex
MeshCollider
on a dynamic Rigidbody for collision and raycasts. Enable Convex, or replace with compound primitives.
Unity会静默忽略动态Rigidbody上的非凸
MeshCollider
进行碰撞和射线检测。启用Convex,或替换为复合基本体。

Step 6 -- Back-face hits

步骤6 —— 背面命中

By default,
Physics.Raycast
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,或确认射线原点位于目标网格的外法线一侧。

XR / UI Raycasts

XR / UI 射线检测

  • GraphicRaycaster
    hits UI Canvas elements only.
  • Physics.Raycast
    hits 3D colliders only.
NEVER use
GraphicRaycaster
when the target is a 3D collider. INSTEAD
Physics.Raycast
for world-space 3D targets.

  • GraphicRaycaster
    仅命中UI Canvas元素。
  • Physics.Raycast
    仅命中3D碰撞器。
当目标是3D碰撞器时,永远不要使用
GraphicRaycaster
。对于世界空间3D目标,应使用
Physics.Raycast
。

5. Build vs Editor Differences

5. 构建与编辑器差异

CauseSymptomFix
IL2CPP stripping MonoBehaviourCallback script removed from buildAdd
[Preserve]
to the class, or add a
link.xml
to preserve the assembly
PhysX initialization orderObjects collide before physics has settledOne-frame delay in
Start()
via coroutine, or manual simulation:
Physics.simulationMode = SimulationMode.Script
+
Physics.Simulate(Time.fixedDeltaTime)
(Unity 2022.2+);
Physics.autoSimulation = false
on older versions
Layer names referenced by string in codeLayer-based filtering fails if a layer name differs between Editor and buildReference layers by index, not string name, in production code
Time.fixedDeltaTime
platform difference
Physics step rate differs between platformsSet Edit > Project Settings > Time > Fixed Timestep explicitly

原因症状修复
IL2CPP剥离MonoBehaviour回调脚本从构建中移除向类添加
[Preserve]
,或添加
link.xml
以保留程序集
PhysX初始化顺序物体在物理稳定之前碰撞在
Start()
中通过协程延迟一帧,或手动模拟:
Physics.simulationMode = SimulationMode.Script
+
Physics.Simulate(Time.fixedDeltaTime)
(Unity 2022.2+);旧版本使用
Physics.autoSimulation = false
代码中以字符串引用图层名称如果图层名称在编辑器与构建之间不同,基于图层的过滤会失败在生产代码中按索引引用图层,而不是字符串名称
Time.fixedDeltaTime
平台差异
不同平台的物理步长不同显式设置 Edit > Project Settings > Time > Fixed Timestep

6. Physics.SyncTransforms

6. Physics.SyncTransforms

When a collider is moved by writing to
transform.position
directly (not via
Rigidbody.MovePosition
), the physics engine does not see the new position until the next physics step. Same-frame queries use the old position.
csharp
transform.position = newPos;
Physics.SyncTransforms(); // forces immediate broadphase update
Physics.Raycast(ray, out hit); // now sees the new position
NEVER call
Physics.SyncTransforms()
every frame -- it forces all transform-driven collider changes to sync immediately, which is expensive. ALWAYS mention both: (1)
Rigidbody.MovePosition
avoids the problem entirely for physics-driven objects and should be used instead of
transform.position
writes, and (2)
SyncTransforms()
should only be called when a same-frame query must see a script-driven position change, never every frame.

当通过直接写入
transform.position
(而不是通过
Rigidbody.MovePosition
)移动碰撞器时,物理引擎直到下一个物理步骤才看到新位置。同帧查询使用旧位置。
csharp
transform.position = newPos;
Physics.SyncTransforms(); // 强制立即更新broadphase
Physics.Raycast(ray, out hit); // 现在看到新位置
永远不要每帧调用
Physics.SyncTransforms()
——它会强制所有transform驱动的碰撞器更改立即同步,这很昂贵。始终同时提及:(1)
Rigidbody.MovePosition
完全避免了物理驱动对象的问题,应优先于
transform.position
写入使用;(2)
SyncTransforms()
只应在同帧查询必须看到脚本驱动的位置更改时调用,绝不能每帧调用。

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:
    Collider.contactOffset
    in the Inspector or via script.
NEVER set
contactOffset
to
0
-- 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.

碰撞器在接触前停止并出现可见小间隙。这就是Contact Offset——一个皮肤宽度,防止PhysX过度穿透。
  • 全局默认:Edit > Project Settings > Physics > Default Contact Offset(默认:
    0.01
    )。
  • 每个碰撞器:检查器中的
    Collider.contactOffset
    或通过脚本设置。
永远不要将
contactOffset
设置为
0
——PhysX需要小的正值;零会导致不稳定和丢失接触。如果视觉上不可接受,请测试稍低的值,或将视觉网格稍微向碰撞器内部偏移以隐藏间隙而不改变物理行为。

8. Time.timeScale and Physics Simulation

8. Time.timeScale 与物理模拟

When
Time.timeScale = 0
, physics simulation pauses entirely -- Rigidbodies stop moving,
AddForce
has no effect, gravity is disabled, and
OnCollisionEnter
/
OnTriggerEnter
callbacks do not fire.
Geometry queries are not affected:
Physics.Raycast
,
Physics.OverlapSphere
, etc. operate on collider geometry directly and continue at
timeScale = 0
. If callbacks have stopped but raycasts still work,
Time.timeScale = 0
is the cause.
Fix: Restore
Time.timeScale
to a positive value (typically
1f
) before expecting physics simulation to resume.

当
Time.timeScale = 0
时,物理模拟完全暂停——Rigidbody停止移动,
AddForce
无效,重力禁用,
OnCollisionEnter
/
OnTriggerEnter
回调不会触发。
几何查询不受影响:
Physics.Raycast
、
Physics.OverlapSphere
等直接作用于碰撞器几何,在
timeScale = 0
时仍然工作。如果回调停止但射线检测仍然有效,
Time.timeScale = 0
就是原因。
修复:在期望物理模拟恢复之前,将
Time.timeScale
恢复为正值(通常为
1f
)。

9. 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
Physics.sleepThreshold
for several fixed frames. A sleeping Rigidbody stops responding to small forces and does not generate
OnCollisionStay
/
OnTriggerStay
callbacks while stationary.
Detect:
Rigidbody.IsSleeping()
returns true; Inspector shows zero velocity in Play Mode.
Fixes:
  1. Call
    Rigidbody.WakeUp()
    before applying a force.
  2. Increase the applied force above the sleep threshold.
  3. Rigidbody.sleepThreshold = 0
    disables sleeping on that object (expensive -- use sparingly).
  4. Global: Edit > Project Settings > Physics > Sleep Threshold.

如果“AddForce在物体静止/落地后失效”,直接应用快速路径6。不要调查输入系统或其他无关子系统。
当速度和角速度低于
Physics.sleepThreshold
持续数个固定帧时,Rigidbody自动进入睡眠状态。睡眠的Rigidbody停止响应小力,并且在静止时不会产生
OnCollisionStay
/
OnTriggerStay
回调。
检测:
Rigidbody.IsSleeping()
返回true;检查器在Play Mode显示零速度。
修复方法:
  1. 在施加力之前调用
    Rigidbody.WakeUp()
    。
  2. 将施加的力增加到超过睡眠阈值。
  3. Rigidbody.sleepThreshold = 0
    禁用该对象上的睡眠(昂贵——谨慎使用)。
  4. 全局:Edit > Project Settings > Physics > Sleep Threshold。

10. Validation

10. 验证

Attach CollisionDebugger.cs to both objects in a suspect pair; remove after diagnosis.
Console outputDiagnosis
Neither object logsIssue in Steps 1-3 (Rigidbody, Layer Matrix, or interaction type)
One object logs, the other does notScript placement issue -- see Section 2 Step 6 / Section 3 Step 5
[2D Collision]
fires
2D components present on an intended 3D setup

将CollisionDebugger.cs附加到可疑对的两个对象上;诊断后移除。
控制台输出诊断
两个对象都没有日志步骤1-3中的问题(Rigidbody、Layer矩阵或交互类型)
一个对象有日志,另一个没有脚本位置问题——参见第2节步骤6 / 第3节步骤5
[2D Collision]
触发
预期3D设置中存在2D组件

11. Resources

11. 资源

-> references/troubleshooting.md
-> references/troubleshooting.md