关于 fix-3d-physics-collisions
用于诊断和修复 Unity 项目中 3D 物理碰撞问题的技能,结合 Unity 版本对应的文档,检查碰撞体、刚体、图层和回调,并针对常见情况提供快速处理路径。
主要功能
- 013D 碰撞诊断流程
- 02检查对应 Unity 版本的文档
- 03检查碰撞体和刚体
- 04排查图层与回调
- 05常见症状快速处理
- 06还原点与改动范围保护
适用场景
- 01诊断碰撞回调未触发
- 02检查物体间的触发器交互
- 03排查布娃娃首帧爆炸
- 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.mdreferences/collision-checklist.mdcollision-debugger.mdother-symptoms.mdraycast-checklist.mdtrigger-checklist.mdscripts/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读取状态。
完整主题索引
在继续工作流或诊断之前:
- 打开并阅读涵盖你计划处理或修复的具体主题的文档页面,并检查是否有遗漏。
- 在回复中列出你阅读的文件名。
这是因为你掌握的 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 版本。
- 使用
unity-cliskill 检查项目的 Unity 版本。 - 如果 Editor 安装目录中有
Data/Documentation文件夹,请在其中的en/ScriptReference文件夹内搜索 html 文件,并跳过其余步骤。 - 否则,获取并缓存
https://docs.unity3d.com/<VERSION>/Documentation/ScriptReference/xrefmap.yml。此文件列出了每个公共 API 成员的完全限定名称,作为uid(例如:uid: 'UnityEngine.Rigidbody.AddForce(UnityEngine.Vector3)')。 - 在本地搜索 yml 文件中的类或方法,而不是每次查找都重新获取。该文件很大(约 6 MB),因此不要读取整个文件。
- 将
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 经常会被标记为过时。
操作步骤
- 调用任何工具之前,请先将提示与 STOP CHECK 快捷路径进行匹配。如果符合其中一项,请给出相应答案,然后转到第 5 步。
- 否则,从
ProjectSettings/ProjectVersion.txt获取 Unity 版本,并检查对象使用了哪些物理组件(Rigidbody、Collider、CharacterController)。如果没有项目或没有版本,则假定使用 Unity 6000.3 和 3D PhysX,并在回答中说明,然后继续。如果用户没有提供要处理的症状、脚本或场景,请向其询问。 - 阅读与该症状相关的文档页面。
- 在 Identify your symptom 中找到该症状,阅读其指向的参考资料,并在 Tool budget 范围内完成处理。
- 如果你更改了项目,请运行 Final step 中的检查。Tool budget 限制的是诊断,不包括这些检查。
- 按照 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:
- 说明这种组合有效,且 Contact Pairs Mode 不会影响它。
- 按以下顺序引导用户检查:
- 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,那就是正确的,请检查其他项目。
- 不要运行
Physics.Simulate()进行验证,因为 Edit 模式下的模拟不会发送 MonoBehaviour 消息。 - 不要获取外部文档——文档与本指南一致。
- 不要建议用户移除 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。 |
最后一步
按顺序运行这些检查。如果任何一项检查失败,请重新阅读文档页面,找出遗漏之处,修复后重新运行检查。
- 使用
console_status检查项目是否没有控制台错误。 - 如果用户没有要求提供证明,而且你不怀疑存在故障,到此为止。
- 否则,进入 Play 模式一次并重现该情况。通过
eval读取用户要求了解的结果,例如子弹的 Rigidbody 位置是否停在墙边,而不只是查看你修改的字段。不要添加日志或截图,因为这会耗费时间并留下改动。 - 退出 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.