Unity物理系统深度解析:从碰撞检测到性能优化的实战指南

📅 2026/7/8 18:34:03
Unity物理系统深度解析:从碰撞检测到性能优化的实战指南
1. 项目概述为什么Unity物理系统值得深挖如果你在Unity里做过游戏尤其是带点动作、解谜或者模拟元素的那你肯定跟物理系统打过交道。可能你只是给一个方块加了个Rigidbody让它自由下落或者给角色加了个Character Controller让它能跳起来。但很多时候我们只是停留在“能用”的阶段——物体掉下去了撞到东西弹开了感觉“物理”生效了任务完成。然而当项目稍微复杂一点比如要做一辆手感真实的赛车、一个布娃娃系统Ragdoll的敌人或者一个需要大量物体交互的沙盒场景时各种诡异的问题就冒出来了物体穿模、性能骤降、运动卡顿、碰撞检测失灵……这时候你才会意识到Unity的物理系统远不止“加个组件”那么简单。我自己在项目里踩过不少坑。最早做一个小球滚动的游戏觉得物理嘛不就是重力加碰撞结果在斜坡上小球时不时会鬼畜抖动甚至飞出去后来做一个FPS游戏手雷的抛物线投掷和爆炸冲击怎么调都觉得“假”再后来接触手机平台面对成百上千个可交互的碎片帧率直接崩盘。这些问题逼着我去深挖Unity物理引擎的底层逻辑、参数意义和最佳实践。我发现很多问题其实官方文档里都有提及但散落在各处缺乏一个从原理到实战、从入门到调优的系统性梳理。所以这篇内容就是把我这些年折腾Unity物理系统积累的经验、踩过的坑和验证过的方案做一个集中的输出。它不仅仅是一份参数说明书更是一个实战指南。我会从最基础的组件讲起拆解它们是如何协同工作的然后深入到物理材质、关节、射线检测等高级话题最后聚焦在性能优化和那些“教科书上不会写”的疑难杂症排查上。无论你是刚接触Unity不久的新手还是已经有一定经验但被物理问题困扰的开发者我相信这里面的内容都能给你带来实实在在的帮助。我们的目标很明确不仅要让物体“动起来”更要让它们“动得对”、“动得好”、“动得高效”。2. 物理系统核心架构与组件深度解析Unity的物理系统不是一个黑盒魔法它是一套由多个核心组件和后台引擎如PhysX共同构成的模拟框架。理解这套架构是解决一切高级问题和进行性能优化的前提。2.1 两大基石碰撞体Collider与刚体Rigidbody这是物理交互的起点。很多新手会混淆两者的职责导致设置错误。碰撞体Collider它只定义了一个物体的“形状边界”用于物理引擎计算碰撞。它本身没有质量不会运动只是一个“区域”。你可以把它想象成一个隐形的、不可穿透的力场外壳。Unity提供了多种基本碰撞体Box, Sphere, Capsule, Mesh等和复合碰撞体由多个基本体组成。注意对于复杂的模型切忌直接使用Mesh Collider并勾选“Convex”以外的选项。非凸Convex的Mesh Collider性能开销极大且只能用于静态物体即不带Rigidbody的物体。对于动态物体应该用多个基本碰撞体Box, Capsule去近似拟合其形状或者确保Mesh是凸的。刚体Rigidbody这是让物体“活”起来的关键。它为物体赋予了物理属性质量Mass、阻力Drag、角阻力Angular Drag并使其受到重力Gravity等力的影响。物理引擎会计算作用在Rigidbody上的所有力和扭矩然后每帧更新它的位置和旋转。核心关系一个物体要参与动态物理模拟比如被力推开、自由落体它必须同时拥有Rigidbody和至少一个Collider。只有Collider没有Rigidbody的物体我们称之为“静态碰撞体”Static Collider比如地面、墙壁它们不会移动但其他动态物体可以撞到它。只有Rigidbody没有Collider的物体……它就是个不受碰撞影响的质点基本没有实用价值。一个常见的误解Is Kinematic选项。勾选后物体不再受物理引擎的力驱动但你仍然可以通过脚本直接修改其Transform.position来移动它并且它依然能与其他动态刚体发生碰撞作为碰撞的主动方。这常用于玩家控制的角色配合Character Controller、移动的平台或者需要被脚本精确控制的物体。关键点Kinematic刚体移动时它会“推开”其他普通动态刚体但自身的运动完全由你掌控。2.2 物理材质Physic Material定义碰撞的“性格”物理材质决定了两个碰撞体接触时的表面行为。它就像给碰撞体表面涂了一层有特定属性的涂料。动态摩擦力Dynamic Friction物体滑动时的摩擦力。值越大停下来越快。想象冰面低摩擦力和砂纸高摩擦力的区别。静态摩擦力Static Friction物体从静止到开始滑动所需克服的摩擦力。通常略大于动态摩擦力。弹力Bounciness碰撞后能量保留的系数。0表示完全非弹性碰撞像橡皮泥粘住1表示完全弹性碰撞理想情况无能量损失。实际应用中大于1的值会导致能量增加物体越弹越高通常用于特殊效果但需谨慎。摩擦力合并模式 弹力合并模式当两个拥有不同物理材质的物体碰撞时如何计算最终的摩擦力和弹力通常使用“Average”平均值或“Multiply”相乘就能满足大多数情况。“Min”和“Max”在某些特定模拟中可能有用。实操心得不要忽视物理材质。一个常见的“滑冰感”问题即角色或物体在平面上停不下来往往就是因为摩擦力设置过低。给地面和角色脚底的碰撞体分配一个合适的物理材质能立刻改善操作手感。对于弹球游戏通过调整弹力可以轻松控制球的活跃程度。2.3 物理引擎的后台PhysX与更新周期Unity默认的3D物理引擎是NVIDIA的PhysX。我们不需要直接操作它但需要理解它的工作节奏。物理模拟是离散的发生在固定的时间步长Fixed Timestep里而不是每一帧渲染的时间。这保证了模拟的稳定性不受帧率波动影响。你可以在Project Settings - Time中找到Fixed Timestep默认是0.02秒即每秒50次物理更新。这意味着什么如果你的游戏逻辑帧率Update是100FPS那么每帧之间物理可能更新了2次FixedUpdate。如果帧率降到25FPS那么每帧之间物理会更新2次以上来“追上”真实时间。这就是为什么你的物理代码比如施加力应该放在FixedUpdate而不是Update里——为了和物理引擎的步调保持一致避免因帧率不同导致力的施加频率变化从而影响物理效果。一个性能陷阱Maximum Allowed Timestep。当游戏卡顿时一帧的耗时可能远超Fixed Timestep。这个参数限制了物理引擎在一帧内用于“追赶”真实时间的最大计算时间。设置得太低物理会显得“变慢”设置得太高则可能在卡顿时导致单帧物理计算过长加剧卡顿。通常保持默认0.333秒即可但对于强调物理稳定性的游戏可能需要微调。3. 碰撞与触发检测的实战应用检测到物体之间的接触是游戏逻辑交互的基础。Unity提供了两套机制碰撞Collision和触发Trigger。3.1 碰撞Collision vs. 触发Trigger这是根本性的区别碰撞两个碰撞体发生物理接触会产生物理反馈力阻挡。双方必须都有非Trigger的Collider且至少一方有Rigidbody。触发两个碰撞体发生体积重叠但不产生物理反馈。只需要将Collider的Is Trigger属性勾选即可。常用于检测区域如拾取物品、进入关卡、伤害区域。如何选择一个简单的判断标准是否需要物理引擎来处理接触后的运动如果需要物体被挡住、弹开用碰撞如果只需要知道“它们碰到了”这个事件然后由游戏逻辑如加分、扣血、播放音效来处理用触发。触发由于不计算物理响应性能开销通常更低。3.2 消息函数与获取信息当碰撞或触发事件发生时Unity会调用对应GameObject上脚本中的特定消息函数。这是你编写交互逻辑的地方。对于碰撞OnCollisionEnter(Collision collisionInfo)碰撞开始的第一帧调用。OnCollisionStay(Collision collisionInfo)碰撞持续的每一帧调用。OnCollisionExit(Collision collisionInfo)碰撞结束的第一帧调用。对于触发OnTriggerEnter(Collider other)进入触发区域的第一帧。OnTriggerStay(Collider other)停留在触发区域的每一帧。OnTriggerExit(Collider other)离开触发区域的第一帧。关键对象Collision和Collider参数包含了丰富的信息。collisionInfo.gameObject/other.gameObject与我发生交互的对方物体。collisionInfo.contacts一个ContactPoint数组包含了碰撞点的位置、法线等信息。这对于计算碰撞后的特效位置如火花、凹痕或者精确的反弹方向至关重要。collisionInfo.relativeVelocity碰撞时双方的相对速度。可以用来计算碰撞的剧烈程度决定播放多大的撞击声效或是否造成破坏。一个实战技巧在OnCollisionEnter中利用relativeVelocity.magnitude来判断碰撞强度。例如void OnCollisionEnter(Collision collision) { float impactStrength collision.relativeVelocity.magnitude; if (impactStrength 5f) { PlaySound(bigCrashSound, impactStrength); // 根据强度调整音量 SpawnParticles(collision.contacts[0].point); // 在碰撞点生成特效 } }3.3 层级碰撞矩阵Layer Collision Matrix这是管理复杂场景中“谁和谁能碰撞”的核心工具。位于Edit - Project Settings - Physics(或 Physics 2D)。为什么需要它想象一个游戏有玩家、敌人、子弹、道具、墙壁、仅装饰用的树叶。你肯定不希望子弹打中队友、玩家捡不到道具因为被碰撞体挡住了、或者角色被一片树叶卡住。通过给不同的物体类型分配不同的Layer并在碰撞矩阵中精确配置你可以完全控制碰撞关系。配置策略创建清晰的Layer不要都用默认的“Default”。创建如“Player”、“Enemy”、“Bullet”、“Pickup”、“Wall”、“Ground”、“Decoration”等。在矩阵中取消勾选例如“Bullet”层不与“Bullet”层碰撞避免子弹互撞“Player”层不与“Pickup”层碰撞但Pickup的Collider是Trigger用于检测“Decoration”层不与任何动态物体碰撞。对性能的影响减少不必要的碰撞检测对性能提升显著。一个“Decoration”层的物体如果它只与“Nothing”层碰撞那么物理引擎几乎会完全忽略它与其他层的碰撞计算。常见问题排查“我的物体明明设置了碰撞体为什么穿过去了” 首先检查的就是Layer Collision Matrix确保这两个物体所在的层之间的复选框是勾选状态。4. 射线检测Raycasting与形状投射Shape Casting这是物理查询的利器用于“主动探测”而非“被动等待碰撞事件”。它们不依赖持续的碰撞检测而是在你需要的时候发射一条射线或一个形状去探测场景。4.1 射线检测Physics.Raycast这是最常用、最高效的查询方式。想象你用手电筒照向黑暗看到光斑落在哪里。基本用法Ray ray new Ray(originPosition, direction); float maxDistance 100f; LayerMask groundLayer LayerMask.GetMask(Ground); RaycastHit hitInfo; // 用于存储击中信息 if (Physics.Raycast(ray, out hitInfo, maxDistance, groundLayer)) { // 击中了“Ground”层的物体 Vector3 hitPoint hitInfo.point; // 击中点 GameObject hitObject hitInfo.collider.gameObject; // 被击中的物体 float distance hitInfo.distance; // 击中距离 }参数解析origin,direction: 定义射线。maxDistance: 射线最大长度避免无谓的远距离计算。layerMask:极其重要通过位掩码指定只检测哪些层。使用LayerMask.GetMask(“Layer1”, “Layer2”)或~(1 layerIndex)来排除某一层。不指定则会检测所有层是性能浪费和逻辑错误的常见根源。queryTriggerInteraction: 指定是否检测Trigger碰撞体。通常使用QueryTriggerInteraction.Ignore来忽略触发器除非你明确需要检测它们。高级用法与变体Physics.RaycastAll: 返回射线路径上所有击中的物体按距离排序。用于霰弹枪、激光穿透等效果。Physics.SphereCast/CapsuleCast/BoxCast: 不是发射一条线而是发射一个形状体。这对于检测一个有体积的物体如角色前方是否有空间移动非常有用避免了角色“嵌进”墙里才发现碰撞。4.2 形状投射在角色控制器中的应用这是实现一个自定义、手感好的角色移动的关键。CharacterController组件内部就大量使用了CapsuleCast。为什么不用简单的Raycast因为角色有体积。一条射线只能检测一个点如果射线从角色中心发出即使射线没碰到墙角色的肩膀可能已经撞上去了。CapsuleCast用一个胶囊体去探测能更准确地反映角色的实际碰撞体积。模拟一个简单的角色移动碰撞检测public CapsuleCollider playerCollider; public float skinWidth 0.1f; // 一层薄薄的“皮肤”用于防止数值误差导致的抖动 bool CanMove(Vector3 direction, float distance) { Vector3 point1 playerCollider.transform.position playerCollider.center Vector3.up * (playerCollider.height/2 - playerCollider.radius - skinWidth); Vector3 point2 playerCollider.transform.position playerCollider.center - Vector3.up * (playerCollider.height/2 - playerCollider.radius - skinWidth); float radius playerCollider.radius - skinWidth; if (Physics.CapsuleCast(point1, point2, radius, direction, out RaycastHit hit, distance)) { // 如果检测到碰撞可以在这里处理滑动例如沿墙面滑动 return false; } return true; }这段代码计算了胶囊体的上下半球心点并考虑了skinWidth来避免在非常接近障碍物时发生高频的“碰撞-分离”抖动。实操心得对于复杂的移动逻辑如平台游戏可能需要组合使用多种检测。例如用Raycast向下检测地面用CapsuleCast向前检测墙壁用SphereCast向下检测悬崖边缘。每一帧根据检测结果来决定角色的速度、是否可跳跃、是否处于爬墙状态等。5. 力、关节与高级物理模拟让物体动起来除了直接设置Transform更符合物理规律的方式是施加力Force和扭矩Torque。而关节Joint则用于模拟物体之间的连接关系。5.1 力的施加方式通过Rigidbody.AddForce()和AddTorque()来施加。ForceMode参数是关键Force: 添加一个持续的力与质量有关。这是最常用的模拟像火箭发动机、风力这样的持续推力。Impulse: 添加一个瞬间的冲量与质量有关。模拟像子弹击中、爆炸冲击、跳跃起跳瞬间的力。Acceleration: 添加一个持续的加速度忽略质量。所有物体获得相同的速度变化。VelocityChange: 添加一个瞬间的速度变化忽略质量。如何选择对于需要根据物体质量产生不同效果的应用重的物体更难推动用Force或Impulse。对于希望所有物体行为一致的应用比如游戏中的一阵风吹动所有纸片和石头用Acceleration或VelocityChange。AddForce通常放在FixedUpdate中以保持力的施加频率稳定。5.2 常用关节Joint详解关节用于约束两个刚体之间的运动关系。Unity内置了多种关节适用于不同场景。固定关节Fixed Joint将两个物体牢固地绑定在一起像焊接一样。适用于组合物体如剑和剑柄当受力超过Break Force阈值时关节会断裂。铰链关节Hinge Joint模拟门、钟摆、杠杆的旋转。你可以设置旋转轴、角度限制、弹簧和马达。一个常见应用是制作可开关的门将门带Rigidbody和Collider通过Hinge Joint连接到门框一个静态Collider。设置旋转轴如Y轴。设置角度限制如-90到90度。可以启用弹簧Spring让它自动回中或者启用马达Motor让它自动旋转。弹簧关节Spring Joint用弹簧连接两个物体。可以设置弹簧的刚度Stiffness和阻尼Damping。适合做绳索、链条的初步模拟或者两个物体之间柔软的连接。注意原生Spring Joint性能一般对于复杂的绳索模拟可能需要专门的插件或自己用多个刚体和关节来模拟。可配置关节Configurable Joint这是最强大、最复杂的关节。它几乎可以模拟任何类型的连接通过分别约束线性位置和角度旋转的自由度。你可以用它来制作自定义的车辆悬挂、布娃娃的肢体连接等。它的学习曲线较陡需要仔细理解每个自由度的含义X Motion, Y Motion, Angular X Motion等。关节使用注意事项关节连接的两个物体通常都需要Rigidbody。关节的Connected Body属性如果为空则默认连接到世界空间World Space。滥用关节尤其是可配置关节会对性能造成较大影响。在移动平台要格外小心。关节的断裂Break Force事件可以通过OnJointBreak(float breakForce)函数来捕获用于播放断裂音效或特效。5.3 布娃娃系统Ragdoll的实现要点布娃娃本质就是一个人形骨骼的每个部位头、躯干、四肢都是一个带碰撞体的刚体然后用关节主要是Character Joint它是简化版的可配置关节把它们连接起来。创建流程使用Unity内置工具准备好带人形动画Humanoid Avatar的模型。在模型根节点上添加Ragdoll组件旧版Unity在GameObject - 3D Object - Ragdoll...。在弹出的向导中将场景中模型骨骼的各个Transform拖到对应的槽位如“Left Hips”拖左髋部的骨骼。调整每个关节的旋转限制Twist/ Swing Limit使其符合人体生理结构比如胳膊不能向后弯。点击“Create”。Unity会自动为每个部位生成碰撞体、刚体和关节。核心控制激活/禁用布娃娃激活时物理关节控制骨骼动画失效。禁用时动画重新控制骨骼。通常通过设置所有刚体的isKinematic来实现切换。isKinematic true时物体不受物理影响可由动画驱动isKinematic false时物体受物理控制。切换时机角色死亡时将isKinematic设为false并通常给某个部位如骨盆或胸部施加一个力来产生倒下的初速度。角色复活时将所有刚体的isKinematic设回true并将骨骼位置对齐到动画姿势。性能与稳定性一个完整的布娃娃通常包含15-20个刚体对CPU是不小的负担。在移动端或需要大量敌人的场景中需考虑对象池和延迟激活例如只在玩家能看到的地方激活布娃娃。关节限制设置不当在高速碰撞下可能导致肢体扭曲成夸张的角度关节“断裂”感。需要仔细调试Break Force和关节的Projection Mode投影模式用于在物理误差过大时强行将关节拉回正确位置。6. 物理性能优化深度指南物理计算是CPU密集型任务尤其是在移动设备或拥有大量动态物理物体的场景中。优化物理性能往往是项目后期的重要攻坚点。6.1 性能瓶颈分析与工具首先你需要知道问题出在哪里。Unity Profiler是你的第一道工具。打开Window - Analysis - Profiler。在CPU Usage区域关注Physics.Processing和Physics.Simulate这两项。如果它们占用的时间很高比如每帧超过5-10ms就说明物理是瓶颈。使用Physics Debugger(Window - Analysis - Physics Debugger 旧版可能在Physics菜单下)。它可以可视化地显示碰撞体的线框。睡眠状态Sleeping的物体显示为蓝色。睡眠的物体物理引擎会跳过计算直到被唤醒。每帧进行的碰撞检测对Pairs。射线和形状投射。通过Physics Debugger你可以一眼看出场景中哪些碰撞体过于复杂、哪些物体在不必要地保持活动状态。6.2 静态与动态碰撞体优化这是最有效的优化手段之一。静态碰撞体Static Collider没有Rigidbody的碰撞体。物理引擎会在场景启动时为所有静态碰撞体构建一个静态碰撞空间数据结构如BVH树。这个构建过程可能较慢但构建完成后与静态碰撞体的检测效率极高。关键点一旦构建完成静态碰撞体绝对不能移动如果移动了整个静态数据结构需要重建会造成严重的性能卡顿。对于需要移动的环境物体如电梯、移动平台必须给它加上Rigidbody并勾选Is Kinematic这样它就被视为动态的但运动由你控制。动态碰撞体Dynamic Collider带有Rigidbody的碰撞体。它们之间的碰撞检测开销远高于与静态碰撞体的检测。因此要尽量减少同时活动的动态碰撞体数量。6.3 刚体睡眠Sleeping与唤醒物理引擎的智能优化。当一个动态刚体的速度低于某个阈值Sleep Threshold并持续一段时间后它会进入睡眠状态。睡眠的刚体几乎不消耗CPU资源。当有足够的力作用其上或与其他物体碰撞时它会被唤醒。如何利用确保你的刚体在静止时能顺利入睡。检查Sleep Threshold默认0.005过高的值会导致物体难以入睡。避免每帧都用AddForce或直接修改velocity去扰动一个本应静止的物体。这会导致它无法入睡。对于一堆堆叠的物体如一堆箱子最下面的箱子承重静止后应该入睡。但如果上面的箱子还在微小的晃动可能会阻止下面的箱子入睡。适当增加Sleep Threshold或调整物理材质摩擦力可能有帮助。6.4 碰撞体复杂度管理碰撞体的形状复杂度直接影响性能开销。优先使用基本碰撞体Box, Sphere, Capsule。它们的计算速度最快。谨慎使用Mesh Collider对于静态环境山体、复杂建筑可以使用非凸的Mesh Collider因为它只在初始化时被烘焙进静态数据结构。对于动态物体必须勾选Convex。非凸的Mesh Collider不能用于动态物体间的碰撞。即使勾选了Convex顶点数也不要太多。使用模型的简化版Low Poly网格来生成碰撞体而不是用渲染网格。可以在3D建模软件中制作一个简化的“碰撞体模型”或者在Unity中通过Mesh Collider的Cooking Options尝试简化。使用复合碰撞体Compound Collider用多个基本碰撞体子物体组合成一个复杂形状远比用一个高面数的凸Mesh Collider高效。例如一个椅子可以用一个盒体做座位四个圆柱做腿。6.5 其他关键优化技巧减少不必要的碰撞检测如前所述善用Layer Collision Matrix。这是免费的午餐能立即剔除大量无用的碰撞计算。调整物理更新频率在Project Settings - Time中增大Fixed Timestep例如从0.02s改为0.04s会降低物理更新的频率从而减轻CPU负担但会降低物理模拟的精度和流畅度。这对于节奏较慢或物理精度要求不高的游戏如卡牌、策略可能是一个可行的权衡。注意这会影响所有基于FixedUpdate的逻辑。控制物理迭代次数在Project Settings - Physics中有Default Solver Iterations和Default Solver Velocity Iterations。求解器迭代次数越高物理约束如关节、穿透纠正计算越精确但开销越大。对于简单场景可以尝试适当降低例如从默认的6降到4。对于有复杂关节或堆叠的场景降低迭代次数可能导致不稳定。使用空间划分与兴趣管理Interest Management对于超大规模物理场景如成千上万个可交互碎片仅靠上述优化不够。需要设计逻辑只对玩家周围一定范围内的物体启用物理Rigidbody设置为Kinematic或直接禁用Collider远处的物体冻结或使用更简单的模拟。这属于游戏逻辑层面的优化。7. 常见疑难问题与实战排查技巧即使理解了原理实际开发中还是会遇到各种奇怪的问题。下面是我总结的一些典型“坑”及其解决方案。7.1 物体抖动或“颤动”Jitter现象两个碰撞体接触时尤其是堆叠时出现高频的微小抖动。原因缩放Scale非均匀碰撞体的局部或全局缩放不是(1,1,1)。物理引擎对非均匀缩放的处理并不完美可能导致碰撞检测异常。碰撞体穿透在某一帧两个物体因为速度过快或其它原因发生了深度穿透。下一帧物理引擎试图将它们推开可能用力过猛导致反向穿透如此循环形成抖动。质量比过于悬殊一个质量极轻的物体放在一个质量极重的物体上轻物体会因为微小的计算误差而不停抖动。解决方案确保所有参与物理的物体其缩放最终为(1,1,1)。如果模型需要缩放考虑在父级空物体上缩放而保持带碰撞体和刚体的子物体缩放为1。增加Fixed Timestep的频率减小数值如从0.02到0.016667对应60FPS可以提高模拟精度减少穿透但会增加CPU开销。为静态碰撞体或质量很大的刚体勾选Rigidbody上的Is Kinematic或者将其质量设置为无限大实际上通过不添加Rigidbody或设为Kinematic实现。使用连续碰撞检测Continuous Collision Detection, CCD。在高速运动的物体如子弹的Rigidbody上将Collision Detection从Discrete离散改为Continuous或Continuous Dynamic。这会追踪物体在两帧之间的运动轨迹防止因速度过快而穿过薄墙。注意CCD开销很大只对少数高速物体使用。7.2 物体“穿模”Passing Through现象物体直接穿过了另一个碰撞体没有触发任何碰撞事件。原因速度过快这是最常见原因。在离散检测中如果物体一帧移动的距离超过其自身尺寸或对方碰撞体的厚度就可能从“墙前”直接跳到“墙后”错过了检测。碰撞体层级设置错误Layer Collision Matrix中两个物体的层没有勾选碰撞。一方是Trigger如果一方是Trigger不会发生物理阻挡物体会直接穿过。刚体被设置为KinematicKinematic刚体不会因碰撞而被物理引擎自动推开除非你在脚本中处理。如果对方是普通动态刚体它会被Kinematic刚体推开但Kinematic刚体自己会“穿”过去。解决方案对高速物体启用CCD如上所述。检查并修正Layer Collision Matrix。明确设计意图是需要物理阻挡Collision还是仅需检测Trigger对于Kinematic刚体如玩家控制器需要在脚本中手动处理碰撞响应。通常使用CharacterController.Move()或自己用Rigidbody.MovePosition()配合碰撞检测来实现。7.3 性能突然下降Spikes现象游戏运行流畅但偶尔会卡顿一下。原因静态碰撞体被移动如前所述移动一个静态碰撞体会触发昂贵的静态物理数据结构重建。大量刚体同时被唤醒例如一场爆炸唤醒了几十个睡眠的刚体导致单帧物理计算量激增。复杂的Mesh Collider生成或销毁。关节断裂Break Force如果有很多用关节连接的物体且关节同时断裂会产生大量新的动态物体增加计算负担。排查与解决使用Profiler定位卡顿帧查看是否是Physics.Processing激增。确保场景中所有不该移动的环境物体都不要挂Rigidbody成为静态碰撞体。对于可移动的环境物体确保其Rigidbody是Kinematic。对于爆炸等会影响大量物体的效果考虑分帧处理唤醒或施加力。使用对象池管理可破碎物体或带关节的物体避免运行时Instantiate和Destroy。7.4 射线检测Raycast相关问题问题1检测不到物体检查发射点和方向是否正确。可以用Debug.DrawRay在Scene视图中可视化射线。检查Layer Mask这是最常出错的地方。确认你传入的Layer Mask包含了目标物体所在的层。检查目标物体的碰撞体是否被禁用collider.enabled false。检查射线的最大距离是否足够。问题2检测到错误的物体如检测到自己在角色自身发射射线检测地面或前方时射线很可能从角色内部的碰撞体发出第一击中的就是自己。解决方案使用Raycast的重载函数传入一个RaycastHit[]数组然后遍历结果跳过hit.collider.transform.IsChildOf(myTransform)的物体。或者更优雅地使用Physics.Raycast的layerMask参数将角色自身的层排除在外int mask ~(1 gameObject.layer);。物理系统的调试是一个需要耐心和逻辑分析的过程。遇到问题时系统地检查组件设置、层级关系、更新函数和性能数据利用好Debug绘制工具大部分问题都能被定位和解决。记住物理模拟是确定性的在相同输入下产生相同结果这为复现和调试问题提供了基础。