mcpField
F
fix-3d-physics-collisions

fix-3d-physics-collisions

github.com/unity-technologies开发1.3k351 次安装今天更新
代码仓库

关于 fix-3d-physics-collisions

用于诊断和修复 Unity 项目中 3D 物理碰撞问题的技能,结合 Unity 版本对应的文档,检查碰撞体、刚体、图层和回调,并针对常见情况提供快速处理路径。

主要功能

  1. 013D 碰撞诊断流程
  2. 02检查对应 Unity 版本的文档
  3. 03检查碰撞体和刚体
  4. 04排查图层与回调
  5. 05常见症状快速处理
  6. 06还原点与改动范围保护

适用场景

  1. 01诊断碰撞回调未触发
  2. 02检查物体间的触发器交互
  3. 03排查布娃娃首帧爆炸
  4. 04处理 CharacterController 碰撞事件问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/unity-technologies/skills --skill fix-3d-physics-collisions

安装后在 Claude Code 中输入/fix-3d-physics-collisions确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

SECURITY.md
references/
collision-checklist.md
collision-debugger.md
other-symptoms.md
raycast-checklist.md
trigger-checklist.md
scripts/
CollisionDebugger.cs

详细介绍

诊断并修复 3D 物理碰撞

重要事项

  • 每个步骤都使用 Unity CLI(unity command --format json)以及 unity-cli 和 unity-pipeline 技能。
  • 在 eval 的 snippet 中不要使用 using 指令或未限定的类型,因为编译器只会读取 using UnityEngine,而直接使用 AssetDatabase 或 Object 会导致错误(CS0246 / CS0103 / CS0104)。使用 return 返回你想要读取的内容;结果会出现在 data.result.result。
  • 创建一个还原点,以便更改失败时可以回滚。
  • 只做要求的工作。不要更改无关的资源或文件。
  • 避免冗长的说明。
  • 不要在用户的脚本中留下验证代码。不要添加用户未要求的日志记录或检测代码,以免项目和控制台变得杂乱。请按照最终步骤中的说明,通过 eval 读取状态。

完整主题索引

在继续工作流或诊断之前:

  1. 打开并阅读涵盖你计划处理或修复的具体主题的文档页面,并检查是否有遗漏。
  2. 在回复中列出你阅读的文件名。

这是因为你掌握的 Unity 知识可能已经过时、有误,或不适用于当前的 Unity 版本。

如果提示匹配停止检查中的快速通道,则跳过此阅读,因为快速通道的回答就是完整回复,且已与这些页面保持一致。

如果 Editor 安装文件夹中有 Data/Documentation 文件夹(例如 ...Unity/Hub/Editor/6000.6.0b2/Editor/Data/Documentation),请阅读 <editor-install>/Editor/Data/Documentation/en/Manual 文件夹中的 html 文件。否则,文档页面位于 https://docs.unity.com/en-us/engine/<VERSION>/manual/。

  • 页面中的链接以 /engine/ 开头。在它们前面添加 https://docs.unity.com/en-us。
  • 如果该 Unity 版本没有对应的页面,请改用 xrefmap.yml 条目中的 href(例如,href: 'Rigidbody.AddForce.html' => https://docs.unity3d.com/<VERSION>/Documentation/ScriptReference/Rigidbody.AddForce.html)。

优先直接获取页面(例如使用 WebFetch),而不是搜索(例如使用 `WebSearch)——这样更快,也能直接定位到准确的参考资料。只获取所需内容;仅在没有准确 URL 时才搜索。

首次获取页面之前,请从 ProjectSettings/ProjectVersion.txt 读取 Unity 版本,因为文档会因版本而异。将文档链接中的 <VERSION> 替换为仅包含主版本号和次版本号的版本(前两个数字),因为完整的构建版本号会导致 404。

  • 碰撞体类型之间的交互 — 本地 collider-types-interaction.html:哪些碰撞体组合会发送碰撞或触发器消息。
  • OnCollision 事件 — 本地 collider-interactions-oncollision.html:Unity 在何时调用 OnCollisionEnter、Stay 和 Exit 事件。
  • OnTrigger 事件 — 本地 collider-interactions-ontrigger.html:触发器碰撞体如何调用 OnTriggerEnter、Stay 和 Exit。
  • 基于图层的碰撞检测 — 本地 LayerBasedCollision.html:在 Layer Collision Matrix 中设置哪些图层会发生碰撞。
  • 选择碰撞检测模式 — 本地 choose-collision-detection-mode.html:为快速移动的对象选择离散或连续检测。
  • 物理设置 — 本地 class-PhysicsManager.html:项目范围的设置,例如 Contact Pairs Mode、Queries Hit Triggers、Invoke Collision Callbacks 和 Simulation Mode。
  • 网格碰撞体组件参考 — 本地 class-MeshCollider.html:Mesh Collider 属性,包括 Convex 和网格烹制选项。
  • 角色控制器组件参考 — 本地 class-CharacterController.html:CharacterController 如何在没有 Rigidbody 的情况下移动和发生碰撞。
API 参考

该 API 包括 Unity Engine 的 UnityEngine.Physics、UnityEngine.Rigidbody、UnityEngine.Collider、UnityEngine.CharacterController 和 UnityEngine.PhysicsScene。它按 Unity 版本划分,因此在依赖特定类或方法之前,请先确认项目使用的 Unity 版本。

  1. 使用 unity-cli skill 检查项目的 Unity 版本。
  2. 如果 Editor 安装目录中有 Data/Documentation 文件夹,请在其中的 en/ScriptReference 文件夹内搜索 html 文件,并跳过其余步骤。
  3. 否则,获取并缓存 https://docs.unity3d.com/<VERSION>/Documentation/ScriptReference/xrefmap.yml。此文件列出了每个公共 API 成员的完全限定名称,作为 uid(例如:uid: 'UnityEngine.Rigidbody.AddForce(UnityEngine.Vector3)')。
  4. 在本地搜索 yml 文件中的类或方法,而不是每次查找都重新获取。该文件很大(约 6 MB),因此不要读取整个文件。
  5. 将 uid 转换为 markdown 页面:移除方括号中的参数,全部改为小写,将 . 替换为 /,并添加 .md。然后获取 https://docs.unity.com/en-us/engine/<VERSION>/script-reference/<converted uid>。例如,UnityEngine.Rigidbody.AddForce(UnityEngine.Vector3) => https://docs.unity.com/en-us/engine/<VERSION>/script-reference/unityengine/rigidbody/addforce.md。所有重载都在同一页面上。
    • 构造函数使用 ctor(例如,unityengine/vector3/ctor.md),索引器使用 item(例如,unityengine/vector3/item.md)。
    • 对于运算符,请获取类页面(例如,unityengine/vector3.md)并查看其中的链接。

请始终使用与项目 Unity 版本对应的文档,而不要依赖训练知识,因为 API 经常会被标记为过时。

操作步骤

  1. 调用任何工具之前,请先将提示与 STOP CHECK 快捷路径进行匹配。如果符合其中一项,请给出相应答案,然后转到第 5 步。
  2. 否则,从 ProjectSettings/ProjectVersion.txt 获取 Unity 版本,并检查对象使用了哪些物理组件(Rigidbody、Collider、CharacterController)。如果没有项目或没有版本,则假定使用 Unity 6000.3 和 3D PhysX,并在回答中说明,然后继续。如果用户没有提供要处理的症状、脚本或场景,请向其询问。
  3. 阅读与该症状相关的文档页面。
  4. 在 Identify your symptom 中找到该症状,阅读其指向的参考资料,并在 Tool budget 范围内完成处理。
  5. 如果你更改了项目,请运行 Final step 中的检查。Tool budget 限制的是诊断,不包括这些检查。
  6. 按照 Required output 中的说明结束回答。如果你更改了项目,请使用 Final report 格式。

关键事实(先阅读,不要推翻)

无论 Contact Pairs Mode 设置如何,两个运动学触发器都会触发 OnTriggerEnter。请相信本指南,不要依赖你之前的认知:

  • Trigger + Kinematic Rigidbody 与另一个 Trigger + Kinematic Rigidbody 是有效组合,运动学触发器与静态碰撞体的组合也有效。碰撞体交互矩阵列出了这两种组合都会发送触发器消息。
  • 不存在单独的触发器矩阵或碰撞矩阵。人们用这些术语指的是 Physics 设置中的Layer Collision Matrix。
  • Contact Pairs Mode(Edit > Project Settings > Physics)决定运动学-运动学和运动学-静态组合是否发送碰撞消息(OnCollisionEnter)。它不会阻止触发器消息,因此不要把它当作触发器问题的解决方法。要检查碰撞相关设置,请读取 ProjectSettings/DynamicsManager.asset 中的 m_ContactPairsMode,因为没有对应的 API getter;然后将该值与 Physics settings 页面中的选项对应起来。

如果用户报告两个运动学触发器没有触发 OnTriggerEnter:

  1. 说明这种组合有效,且 Contact Pairs Mode 不会影响它。
  2. 按以下顺序引导用户检查:
    • Layer Collision Matrix(Edit > Project Settings > Physics),以及每个 Collider 和 Rigidbody 上的 Layer Overrides(Include Layers 和 Exclude Layers);它们的优先级高于矩阵。
    • 脚本位置:回调必须位于触发器 GameObject 或进入触发器的对象上。
    • 方法签名:OnTriggerEnter(Collider other),末尾不要带 2D。
    • 移动方式:使用 Rigidbody.MovePosition() 或写入 transform.position 来移动运动学 Rigidbody。运动学刚体不会受 Rigidbody.linearVelocity 驱动,因此由速度驱动的运动学刚体永远不会到达另一个触发器。如果用户使用的是 MovePosition,那就是正确的,请检查其他项目。
  3. 不要运行 Physics.Simulate() 进行验证,因为 Edit 模式下的模拟不会发送 MonoBehaviour 消息。
  4. 不要获取外部文档——文档与本指南一致。
  5. 不要建议用户移除 Rigidbody、将运动学改为动态或更改架构——当前设置有效。

必须遵守的输出要求

每次调用都必须以面向用户的答复结束,说明诊断结果和解决方法,因为仅调用工具对用户没有帮助。

立即停止:任何类型的工具调用达到 5 次后,立即停止调用工具,并根据 Fast-Paths 或检查清单给出最可能的诊断,即使尚未完全确认也要如此。

不要征求许可:绝不要以“要我继续吗?”或类似措辞结尾。如果脚本位于项目中,或已连接 Editor,就直接编辑脚本或通过 Editor 修改场景来应用修复。否则,提供完整且自成一体的说明。不要提问,以免让用户多花一轮时间。

停止检查——任何工具调用前先进行匹配

调用任何工具前,先对照下方 Fast-Paths 检查用户的提示。第一个匹配项就是完整答复——写出答复并停止。不要搜索项目、读取文件、检查场景、在 Editor 中运行 C# 或获取文档,因为这些答案都已验证。

快速处理 1 —— 2D 物理或 DOTS
  • 2D 物理(Rigidbody2D、Collider2D、OnCollisionEnter2D、Physics2D):如果已安装 create-2d-physics 技能,请改用该技能,因为它涵盖两种 2D 物理系统。否则请说明本技能仅涵盖 3D 物理,然后停止。
  • DOTS(PhysicsCollider、ICollisionEventsJob、ITriggerEventsJob、Unity.Physics、Havok、ECS、Entities):如果已安装 physics-dots 技能,请改用该技能。否则,先用一句话说明 DOTS 物理不在本技能范围内,再尽力简要解答,并使用 DOTS API(PhysicsBody、PhysicsCollider、ICollisionEventsJob、SimulationSingleton),最后附上一个文档链接。

不要将 3D PhysX 或 MonoBehaviour 规则用于这些问题,也不要建议切换物理系统。

快速处理 2 —— 两个运动学触发器未触发 OnTriggerEnter

如果两个对象都是运动学对象,且都是触发器:请先检查图层,然后应用 关键事实 响应。

快速处理 3 —— 布娃娃在第 1 帧无外力时爆炸

如果布娃娃、带关节的刚体或角色在无外力时于第 1 帧弹飞或爆炸:

  • 原因:碰撞体重叠会导致一帧的退穿透速度尖峰。
  • 修复方法:缩小布娃娃碰撞体,确保它们在初始姿势下互不重叠。明确说明这是唯一的主要修复方法。
  • 请用户打开 Window > Analysis > Physics Debugger 进行确认。它会在第 1 帧突出显示重叠的碰撞体对。
  • 即使提示中提到关节限制、关节投影、关节配置、关节类型、质量比或驱动参数,也不要将它们列为原因,因为这些都不会导致此症状。
  • 不要建议将关节上的 Enable Collision 设为禁用作为主要修复方法,因为这只会掩盖重叠,并未消除重叠。
快速处理 4 —— CharacterController + OnCollisionEnter 未触发

如果移动对象使用 CharacterController,而用户预期 OnCollisionEnter 会触发:

  • 通过 CharacterController.Move() 移动时,OnCollisionEnter 永远不会触发。应改用 OnControllerColliderHit(ControllerColliderHit hit)。
  • 不要建议添加 Rigidbody,因为同一对象上的 CharacterController 和 Rigidbody 会争夺其移动控制权。
快速处理 5 —— 对象静止后 AddForce 不再生效

如果对象落地或停止后,AddForce 或 AddTorque 不再生效:

  • 原因:Rigidbody 进入休眠状态。
  • 修复方法:在调用 AddForce 前调用 Rigidbody.WakeUp()。直接应用代码修改,不要更改 Input System 或其他无关代码。
快速处理 6 —— 所有物理模拟都已冻结,但射线检测仍有效

如果回调已停止,力和重力也不起作用,但 Physics.Raycast 仍能命中:Time.timeScale 为 0。请将其恢复为 1f,通常在暂停菜单或过场控制器中设置。

快速处理 7 —— 射线起点位于目标碰撞体内部

如果Physics.Raycast 返回 false,且射线从目标内部开始:请阅读 Physics.Raycast 页面中的说明,然后将起点移到碰撞体外部。不要建议使用 Queries Hit Backfaces,因为它无法解决这种情况。

快速处理 8 —— 射线检测未命中非活动 GameObject 或已禁用的 Collider

如果目标 GameObject 处于非活动状态,或其 Collider 已禁用:射线检测会忽略它。请确保在执行射线检测前,gameObject.activeInHierarchy 和 Collider.enabled 均为 true。

快速排查 9——Raycast 未检测到触发器

如果 Physics.Raycast 未检测到触发器碰撞体:在该调用中传入 QueryTriggerInteraction.Collide,因为它会覆盖 Queries Hit Triggers。请参阅 QueryTriggerInteraction 和 Physics 设置。

快速排查 10——IgnoreLayerCollision 的抑制效果持续到切换场景后

如果 Physics.IgnoreLayerCollision 意外地抑制了碰撞,或其效果持续到切换场景后:优先建议使用 Layer Collision Matrix(Edit > Project Settings > Physics),因为它设置明确,且不依赖运行时调用。作为仅通过代码实现的备用方案,可在场景加载时调用 Physics.IgnoreLayerCollision(layerA, layerB, false)。

工具调用预算

对于快速排查未涵盖的情况:提交答案前最多调用 5 次工具。不要在 Editor 中运行 C#,也不要为了重新核查本技能中已列明的规则而获取文档,因为这些规则已经过验证。

确定症状

阅读与用户症状相符的参考文件:

  • 碰撞检查清单 - 当 OnCollisionEnter、Stay 或 Exit 未触发,或物体彼此穿过时阅读。第 10 步涵盖只在高速运动时发生的碰撞失效。
  • 触发器检查清单 - 当 OnTriggerEnter、Stay 或 Exit 未触发时阅读。此清单会检查 Is Trigger、Rigidbody 规则、图层、回调签名和位置,以及非凸网格触发器。
  • Raycast 检查清单 - 当 Physics.Raycast 未命中物体时阅读。此清单会检查 LayerMask、非凸网格碰撞体、背面和 UI 目标。
  • 其他症状 - 当物理在 Editor 中正常、但在构建版本中异常,移动后的碰撞体直到下一步才被检测到,接触前出现明显间隙,或刚体不再响应时阅读。
  • 碰撞调试器 - 当用户想查看物理系统报告了哪些接触点,或检查清单无法确认原因时阅读。它会在 Editor 中记录接触点,不会向场景中添加任何内容;之后请将其删除。

控制台错误

如果用户的 Console 显示以下错误之一,请应用对应行中的修复,因为在原因解决之前,Unity 不会为该碰撞体创建物理形状(或会保留旧值)。

错误文本根本原因修复方法
"Concave Mesh Colliders are not supported when used with dynamic Rigidbody GameObjects"非运动学 Rigidbody 上的非凸 MeshCollider,导致物体穿过其他碰撞体,且射线检测无法命中。在 MeshCollider 上启用 Convex。否则,如果凸包过于粗糙,请改用复合基本碰撞体。
"Concave Mesh Colliders are not supported when used with the Is Trigger option enabled"启用了 Is Trigger 的非凸 MeshCollider,导致触发器始终不会触发。在 MeshCollider 上启用 Convex。
"Contact offset must be greater than zero"脚本或 Inspector 将 contactOffset 设为 0 或更小,而 Unity 保留了旧值。设置一个较小的正值,例如 0.001。

最后一步

按顺序运行这些检查。如果任何一项检查失败,请重新阅读文档页面,找出遗漏之处,修复后重新运行检查。

  1. 使用 console_status 检查项目是否没有控制台错误。
  2. 如果用户没有要求提供证明,而且你不怀疑存在故障,到此为止。
  3. 否则,进入 Play 模式一次并重现该情况。通过 eval 读取用户要求了解的结果,例如子弹的 Rigidbody 位置是否停在墙边,而不只是查看你修改的字段。不要添加日志或截图,因为这会耗费时间并留下改动。
  4. 退出 Play 模式,再次检查控制台是否没有错误。

最终报告

向用户提供一份简短清单,说明你做了什么以及原因。列出所有副作用,例如你修改的项目设置,或添加后又移除的临时脚本。如果用户还需要执行后续步骤或作出决定,请列出。例如:

I made the following changes:

[✓] Set the bullet Rigidbody's Collision Detection to Continuous Speculative, because it moved far enough in one physics step to pass through the wall.

Follow these steps to see the effect:

1. Enter Play mode and fire at the wall.
2. Check the bullet stops at the wall instead of passing through it.

评论

支持 Markdown