Unity物理系统核心:Collider与Rigidbody五大误区深度解析
1. 项目概述:为什么新手总在物理组件上栽跟头?
刚接触Unity开发,尤其是开始捣鼓角色移动、物体碰撞这些基础交互时,Collider(碰撞器)和Rigidbody(刚体)这两个组件几乎是绕不开的。它们就像是游戏世界物理法则的“翻译官”和“执行者”。Collider负责告诉Unity:“我这个物体有形状,会占地方,别的东西不能穿过去。”而Rigidbody则告诉Unity:“我这个物体有质量,受重力影响,可以被力推动。”听起来很简单,对吧?但恰恰是这种“简单”,让无数新手开发者,包括当年的我,踩进了各种意想不到的坑里。
我见过太多项目,角色卡在墙角、物体莫名穿透、物理表现飘忽不定,追根溯源,十有八九是Collider和Rigidbody的设置出了问题。这些问题往往不是代码逻辑错误,而是对这两个组件底层工作机制的理解偏差。比如,你以为给一个物体加了Rigidbody它就应该乖乖下落,结果它却纹丝不动;你以为两个都有Collider的物体放一起就会碰撞,结果它们却“相安无事”地穿模而过。这些现象背后,是Unity物理引擎(默认是NVIDIA PhysX)一套严谨但稍显复杂的运行规则。
这篇文章,就是把我自己以及身边同事、学员在项目实战中反复遇到的、关于Collider和Rigidbody的五个最具代表性的“坑”给挖出来,掰开揉碎了讲清楚。我们的目标不是复述官方手册,而是用最直白的语言,解释这些误区“为什么”会发生,并给出经过项目验证、拿来即用的解决方案。无论你是在做一款2D平台跳跃游戏,还是一个需要真实物理反馈的模拟应用,理解这些内容都能帮你省下大量调试时间,让物体的行为更符合你的预期。
2. 核心误区拆解与深度解决方案
2.1 误区一:以为只要加了Collider,物体就能碰撞
这是最经典的入门级误区。很多新手会想当然地认为:我给两个GameObject都挂上了Box Collider,把它们放到一起,它们就应该发生碰撞并被阻挡。
为什么不行?在Unity的物理世界里,碰撞检测(Collision Detection)和碰撞解析(Collision Resolution)是两回事。Collider只解决了“检测”问题——即物理引擎能知道两个物体的形状发生了重叠。但是,当重叠发生时,该如何处理?是弹开、是滑动、还是粘住?这个“处理”的职责,主要由Rigidbody来承担。更准确地说,至少需要其中一个碰撞参与者拥有Rigidbody组件,物理引擎才会去计算并应用碰撞响应(如力、速度改变)。
你可以把Collider想象成物体的“皮肤”或“轮廓”,它只定义了形状。而Rigidbody是物体的“物理属性核心”,它决定了这个物体如何参与物理模拟(是动态的、受力的,还是静态的、作为场景的一部分)。
解决方案与实操要点
明确角色定位:在规划场景中的物体时,就要想清楚它的物理角色。
- 动态碰撞体(Dynamic Collider):需要移动、受力的物体。必须附加Rigidbody组件,并且Collider会随着物体的Transform移动而移动。例如:玩家角色、被抛出的球、可被推开的箱子。
- 静态碰撞体(Static Collider):固定不动、作为环境一部分的物体。不需要附加Rigidbody组件。例如:地面、墙壁、固定的台阶。Unity会对静态碰撞体进行优化,但请注意,一旦在运行时通过代码改变了带有Collider(无Rigidbody)的物体的Transform位置,它就会自动被转换为“动态”处理,效率会降低。
- 运动学碰撞体(Kinematic Collider):需要通过代码(而非物理力)精确控制其运动的物体。需要附加Rigidbody组件,但必须勾选
Is Kinematic。例如:移动的平台、由动画控制的电梯。它不会受重力等力的影响,但可以推动其他动态刚体。
一个快速检查清单:
- 两个物体要产生“碰撞阻挡”效果,至少其中一个必须有Rigidbody。
- 如果希望A物体被B物体撞飞,那么A必须是动态刚体(有Rigidbody,
Is Kinematic为false)。 - 如果希望A物体(如玩家)在B物体(如地面)上行走,那么玩家是动态刚体,地面可以是静态碰撞体(只有Collider)或运动学刚体。
注意:还有一种特殊情况是
Trigger(触发器)。当Collider的Is Trigger被勾选时,无论有无Rigidbody,它都不会产生物理阻挡,而是会穿透并发送OnTriggerEnter等消息。这常用于检测区域、拾取物品,是另一种设计模式,不要与常规碰撞混淆。
2.2 误区二:Rigidbody的Drag和Angular Drag就是“摩擦力”
很多开发者,尤其是从一些简单物理模型转过来的,会下意识地把Rigidbody组件上的Drag(阻力)和Angular Drag(角阻力)参数等同于现实世界的“地面摩擦力”。这是一个非常容易导致物理手感调校失败的误解。
为什么不是?
- Drag(线性阻力):它模拟的是物体在运动中所受的介质阻力,比如空气阻力或水阻力。它的作用是在任何运动方向上,持续地减缓物体的线性速度。无论物体是在空中飞行还是在地面滑动,只要速度不为零,Drag就会起作用。它并不区分物体是否接触地面。
- Angular Drag(角阻力):同理,它模拟的是旋转时所受的介质阻力,持续减缓物体的旋转速度。
- 真实的摩擦力:在Unity的物理引擎中,摩擦力是通过物理材质(Physics Material)来定义的,并应用于Collider之间。它只在两个Collider接触时才会产生,方向与接触面相对运动趋势相反,其大小与接触面的法向力(通常是重量)和摩擦系数有关。
解决方案与实操要点
正确使用Drag:Drag非常适合用来模拟一些“手感”。例如,你想让一个太空中的物体移动起来有惯性但又不会永远滑下去,可以设置一个较小的Drag(如0.1~0.5)。如果你想模拟水下运动,可以设置一个较大的Drag(如2~5)。但不要指望用它来让角色在地面上快速停下,那会导致在空中移动时也感觉粘滞。
配置物理材质实现摩擦力:
- 在Project视图中右键 -> Create -> Physics Material (3D) 或 Physics Material 2D (2D)。
- 关键参数:
Dynamic Friction(动摩擦系数):物体滑动时的摩擦力。Static Friction(静摩擦系数):物体从静止到开始滑动所需的摩擦力。Bounciness(弹性):碰撞后的反弹程度。
- 将创建好的物理材质,拖拽到物体Collider组件的
Material属性槽中。 - 实例:为了让一个箱子在地面上滑动一段距离后停下,你需要为地面和箱子的Collider分配合适的物理材质,并调整摩擦系数。同时,箱子的Rigidbody的Drag可以设置为一个很小的值(如0.05),仅用于模拟微小的空气阻力。
一个综合调整案例——冰面与泥沼:
- 冰面效果:创建一个物理材质,将
Dynamic Friction和Static Friction都设得很低(如0.05)。赋予给地面Collider。此时,即使角色Drag很低,站在上面也极易打滑。 - 泥沼效果:创建一个物理材质,将两个摩擦系数设得很高(如0.8)。同时,增大角色Rigidbody的Drag(如1.5)和Angular Drag(如1.0),这样角色在泥沼中移动时,不仅受到地面的高摩擦,还受到介质的“粘滞”阻力,移动和转身都会非常困难。
- 冰面效果:创建一个物理材质,将
2.3 误区三:用Transform直接移动带有Rigidbody的物体
这是性能问题和诡异物理现象的万恶之源之一。新手常常会写这样的代码来控制玩家移动:transform.Translate(Vector3.forward * speed * Time.deltaTime);或者transform.position += moveDirection * speed * Time.deltaTime;。当物体没有Rigidbody时,这没问题。但一旦挂上了Rigidbody,这就是“越权”操作。
为什么不能这么做?Unity的物理引擎(PhysX)在一个独立的线程中运行,它维护着自己的一套物体位置、旋转和速度数据。当你直接修改Transform组件时,你是在主线程中修改另一套数据。在每一帧的FixedUpdate(物理更新)循环中,物理引擎会去同步这些数据,但这个过程可能导致:
- 性能开销:物理引擎需要不断检测Transform的变化并同步,破坏了其内部的预测和优化。
- 穿透问题:如果你在一帧内用Transform将物体移动了很长距离,物理引擎在下一帧同步时可能会发现物体已经“穿越”了另一个碰撞体,从而错过碰撞检测。这就是所谓的“子弹穿透”问题。
- 物理响应异常:物体可能表现出不符合物理规律的行为,比如撞墙后抖动、施加力无效等,因为位置信息被外部代码强行覆盖。
解决方案与实操要点对于带有Rigidbody的物体,正确的移动方式是通过力(Force)或直接设置速度(Velocity)。
使用力(AddForce)—— 模拟真实物理驱动这是最符合物理规律的方式,适合模拟车辆、球体、被爆炸冲击的物体等。
public class PlayerMovement : MonoBehaviour { public float moveForce = 10f; private Rigidbody rb; void Start() { rb = GetComponent<Rigidbody>(); } void FixedUpdate() // 物理操作务必在FixedUpdate中进行! { float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); Vector3 force = new Vector3(horizontal, 0, vertical) * moveForce; rb.AddForce(force); } }- ForceMode选择:
AddForce有几种模式,ForceMode.Force(持续力,默认)、ForceMode.Impulse(瞬间冲量)、ForceMode.Acceleration(忽略质量施加加速度)、ForceMode.VelocityChange(忽略质量改变速度)。根据场景选择。
- ForceMode选择:
直接修改速度(velocity)—— 实现精确控制当你需要非常直接、即时地控制移动,比如平台游戏角色跳跃、太空射击游戏飞船移动时,直接设置
velocity更合适。public class PlatformerMovement : MonoBehaviour { public float moveSpeed = 5f; public float jumpForce = 7f; private Rigidbody rb; private bool isGrounded; void Start() { rb = GetComponent<Rigidbody>(); } void Update() { // 跳跃检测通常在Update中 if (Input.GetButtonDown("Jump") && isGrounded) { rb.velocity = new Vector3(rb.velocity.x, jumpForce, rb.velocity.z); } } void FixedUpdate() { float horizontal = Input.GetAxis("Horizontal"); // 直接设置水平速度,保持垂直速度不变(用于重力作用) rb.velocity = new Vector3(horizontal * moveSpeed, rb.velocity.y, 0); } void OnCollisionEnter(Collision collision) { /* 检测地面... */ } }- 关键点:直接设置
velocity会完全覆盖物理引擎计算出的该方向速度,因此要小心处理。上面的例子中,我们只替换了X轴速度,而保留了Y轴速度(由重力和跳跃影响),这是平台游戏的常见做法。
- 关键点:直接设置
运动学刚体(Is Kinematic)的移动如果物体勾选了
Is Kinematic,那么它不受物理力影响,但可以通过移动其Transform来驱动,并且能影响其他非运动学刚体。这通常用于移动平台。public class MovingPlatform : MonoBehaviour { public Vector3 moveDirection; public float speed; private Rigidbody rb; void Start() { rb = GetComponent<Rigidbody>(); } void FixedUpdate() { // 对于Kinematic刚体,直接移动Transform是允许且常见的 // 物理引擎会处理它与其他物体的碰撞 rb.MovePosition(transform.position + moveDirection * speed * Time.fixedDeltaTime); } }MovePositionvstransform.position:对于运动学刚体,虽然可以直接改transform.position,但使用Rigidbody.MovePosition()是更推荐的做法,因为它会让物理引擎更平滑地处理这次移动。
2.4 误区四:忽视Collider之间的层级关系(Layer Collision Matrix)
你可能会遇到这种情况:明明给子弹和敌人都设置了Collider和Rigidbody,子弹却直接穿过了敌人,没有任何碰撞事件发生。或者,玩家的脚部碰撞体(用于检测地面)总是和自己的身体发生碰撞,导致角色把自己“绊倒”。这些问题,很可能出在图层碰撞矩阵(Layer Collision Matrix)上。
为什么会发生?Unity为了性能优化,允许你精细地控制哪些层(Layer)的物体可以和哪些层的物体发生碰撞。所有GameObject都分配在一个图层中(默认是“Default”)。如果两个物体的图层被设置为互不碰撞,那么即使它们都有Collider和Rigidbody,物理引擎也会完全忽略它们之间的碰撞检测。
解决方案与实操要点
理解并配置图层碰撞矩阵
- 菜单栏:
Edit->Project Settings->Physics(3D) 或Physics 2D(2D)。 - 你会看到一个巨大的矩阵表格,行和列都是所有的图层。勾选框表示这两个图层会发生碰撞,取消勾选则表示忽略碰撞。
- 默认情况:“Default”层与所有层(包括自身)都是碰撞的。
- 菜单栏:
实战应用:设置图层和碰撞关系假设我们有一个简单的2D射击游戏:
- 步骤1:创建新图层。在Inspector顶部的Layer下拉框中,选择
Add Layer...,创建几个新层,例如:Player,Enemy,PlayerBullet,EnemyBullet,Ground,IgnoreRaycast(Unity内置,常用来放视觉特效等不参与碰撞的物体)。 - 步骤2:分配图层。将玩家GameObject的图层设为
Player,敌人设为Enemy,子弹分别设为PlayerBullet和EnemyBullet,地面设为Ground。 - 步骤3:配置碰撞矩阵。打开
Physics 2D Settings。- 取消
Player和PlayerBullet的碰撞(避免玩家被自己的子弹打中)。 - 取消
Enemy和EnemyBullet的碰撞。 - 确保
PlayerBullet和Enemy是碰撞的(玩家子弹能打中敌人)。 - 确保
EnemyBullet和Player是碰撞的。 - 确保
Player、Enemy和Ground都是碰撞的。 - 可以将
IgnoreRaycast层与所有其他层的碰撞都取消,专门用于放置不需要物理交互的物体。 通过这样的设置,你可以用极低的性能开销实现复杂的碰撞关系,而无需在代码中写一堆if判断。
- 取消
- 步骤1:创建新图层。在Inspector顶部的Layer下拉框中,选择
使用代码动态忽略碰撞有时,碰撞关系需要在运行时改变。可以使用
Physics.IgnoreCollision或Physics2D.IgnoreCollision。// 忽略两个特定碰撞体之间的碰撞 public Collider2D playerCollider; public Collider2D friendlyNpcCollider; void Start() { Physics2D.IgnoreCollision(playerCollider, friendlyNpcCollider, true); // true表示忽略 }- 注意:这个方法作用于具体的Collider实例,比图层矩阵更灵活但管理起来更复杂。通常优先使用图层矩阵进行全局管理。
2.5 误区五:对Collision Detection(碰撞检测模式)的误解
当物体高速移动时(比如子弹、发射的炮弹、快速挥动的武器),即使你用了Rigidbody和正确的移动方法,仍然可能发生“穿透”。这是因为在默认的Discrete(离散)检测模式下,物理引擎只在每个固定的物理时间步长(Fixed Timestep)检查一次碰撞。如果物体在一帧内移动的距离超过了自身碰撞体的尺寸,它就可能“跳过”另一个碰撞体。
不同模式的区别
- Discrete(离散):默认模式。性能最好,只在每个物理时间步检查碰撞。适用于中低速运动的物体。
- Continuous(连续):对带有Rigidbody的物体进行连续碰撞检测(CCD),可以防止高速物体穿透静态碰撞体(无Rigidbody)。但无法防止两个都是动态刚体的高速物体相互穿透。性能开销较大。
- Continuous Dynamic(连续动态):最严格的模式。不仅对静态碰撞体,对设置为
Continuous或Continuous Dynamic的动态刚体也进行连续检测。能有效防止高速动态物体间的穿透。性能开销最大。 - Continuous Speculative(连续推测):Unity较新版本引入的一种模式,通过推测轨迹来检测碰撞,在性能和效果间取得平衡,通常作为
Continuous的替代选项。
解决方案与实操要点
根据物体速度合理选择模式
- 低速/环境物体:保持
Discrete即可。 - 高速运动的子弹(对抗静态环境):将子弹Rigidbody的
Collision Detection设置为Continuous。这样它能检测到与地面、墙壁等静态碰撞体的碰撞。 - 高速运动的飞船(可能与其他高速物体相撞):将所有可能高速相撞的物体的Rigidbody都设置为
Continuous Dynamic。这是防止穿透最有效但最耗性能的方法。
- 低速/环境物体:保持
一个折中的优化技巧如果因为性能考虑不能大量使用
Continuous Dynamic,可以尝试:- 增大碰撞体:对于高速飞行的子弹,可以适当增大其Collider的尺寸(例如,Sphere Collider的半径),使其在物理步长内的移动距离不会超过其“检测范围”。这被称为“牺牲精度换性能”。
- 使用射线检测辅助:对于非常重要的高速碰撞(如玩家发射的主武器),可以在用
Transform移动的同时,每帧发射一条从上一帧位置到当前位置的射线(Raycast)或扫描一个形状(SphereCast,BoxCast)进行手动检测。这比全局开启连续检测更高效,但代码更复杂。
// 一个简化的子弹射线检测思路 void FixedUpdate() { Vector3 previousPosition = transform.position; rb.MovePosition(transform.position + direction * speed * Time.fixedDeltaTime); // 用物理方式移动 float distanceMoved = Vector3.Distance(previousPosition, transform.position); RaycastHit hit; if (Physics.Raycast(previousPosition, direction, out hit, distanceMoved)) { // 如果射线击中了什么,说明可能发生了穿透,手动处理碰撞 OnHitDetected(hit.collider); } }调整Fixed Timestep在
Edit -> Project Settings -> Time中,可以找到Fixed Timestep(默认0.02秒,即每秒50次物理更新)。减小这个值(如0.01秒)会增加物理更新的频率,使得每一帧内物体移动的距离变短,从而降低穿透概率,但会显著增加CPU负担。这通常是在调整碰撞检测模式后仍无法解决问题时的最后手段,需谨慎使用。
3. 进阶配置与性能优化实战
理解了上述五个核心误区,你已经能解决90%的常见问题。但要打造流畅、稳定的游戏体验,还需要关注一些进阶配置和性能优化点。
3.1 Rigidbody的Interpolation与Sleep状态
插值(Interpolation):如果你发现带有Rigidbody的物体运动时有抖动,尤其是在Update里渲染的位置和FixedUpdate里计算的位置不同步时,可以尝试修改Rigidbody的
Interpolation属性。None:无插值。可能出现抖动。Interpolate:根据上一帧和当前帧的物理位置进行插值,使渲染平滑。这是最常用的选择,适用于由物理驱动的主要运动物体(如玩家角色)。Extrapolate:根据当前帧物理位置和速度预测下一帧位置。在物理计算不稳定时可能产生“跳跃感”,一般较少用。- 实操建议:给主摄像机跟随的玩家角色Rigidbody加上
Interpolate,画面流畅度会立即提升。
休眠(Sleeping):这是物理引擎一个重要的性能优化功能。当一个动态刚体的速度低于某个阈值并持续一段时间后,它会进入“休眠”状态,物理引擎将不再计算它的运动,直到有外力将它“唤醒”。你可以在Rigidbody组件上看到
Sleeping Mode选项。Never Sleep:永不休眠。除非必要(如持续受力的物体),否则不要用,非常耗性能。Start Awake/Start Asleep:初始状态。通常保持默认Start Awake即可。- 注意:如果你通过代码直接设置一个休眠刚体的
velocity或position,它会自动被唤醒。但如果你发现某个应该运动的刚体“卡住”不动了,可以检查一下它是否意外进入了休眠状态(rb.IsSleeping()),必要时用rb.WakeUp()手动唤醒。
3.2 复合碰撞体与触发器的高效使用
复合碰撞体(Compound Colliders):一个GameObject可以添加多个Collider组件来组合成复杂形状,这比使用一个复杂的Mesh Collider(网格碰撞体)效率高得多。例如,一个人形角色可以用一个胶囊体作为身体,两个球体作为手,一个盒体作为脚。
- 优点:性能远优于单一Mesh Collider,形状更可控,物理反馈更稳定。
- 注意:所有子碰撞体共享同一个GameObject的Rigidbody物理属性。
触发器的正确使用姿势:触发器(
Is Trigger)不产生物理力,只发送消息。用好触发器能实现很多游戏逻辑。- 消息方法:
OnTriggerEnter(Collider other),OnTriggerStay,OnTriggerExit。对应的2D方法是OnTriggerEnter2D(Collider2D other)等。 - 典型应用:
- 拾取物品:物品是触发器,玩家进入范围即拾取。
- 检测区域:进入某个区域触发剧情、刷怪、改变音乐。
- 技能范围:判断敌人是否在技能作用范围内。
- 性能提示:避免在
OnTriggerStay内每帧执行复杂运算(如寻路、大量数学计算)。如果需要持续检测,可以设置一个标志位,在OnTriggerEnter里设为true,在OnTriggerExit里设为false,然后在Update里根据标志位执行逻辑。
- 消息方法:
3.3 物理材质与摩擦、弹性的微调
前面提到了物理材质,这里再深入一下它的高级用法。
- Friction Combine(摩擦合并模式)和Bounce Combine(弹性合并模式):当两个拥有不同物理材质的物体碰撞时,如何计算最终的摩擦力和弹性?这里有四个选项:
Average:取平均值。(最常用)Minimum:取最小值。Maximum:取最大值。Multiply:相乘。 例如,一个“冰面”材质(摩擦0.1)和一个“橡胶”材质(摩擦0.8)碰撞,如果使用Average,则摩擦力约为0.45;如果使用Minimum,则摩擦力为0.1(非常滑)。你可以利用这个特性创造特殊效果,比如让某种材质的物体无论碰到什么都变得很滑(设置其合并模式为Minimum)。
4. 常见问题排查与调试技巧实录
即使理解了所有原理,实际开发中还是会遇到各种稀奇古怪的问题。下面是我从实际项目中总结的一些排查清单和调试技巧。
4.1 问题速查表
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 物体直接穿透,无碰撞 | 1. 至少一方没有Rigidbody。 2. 图层碰撞矩阵未勾选。 3. Collider的 Is Trigger被勾选。 | 1. 检查双方Inspector,确保至少一方有Rigidbody。 2. 检查 Edit -> Project Settings -> Physics中的Layer Collision Matrix。3. 取消勾选 Is Trigger(如果不需要触发器功能)。 |
| 物体抖动或剧烈震颤 | 1. 两个碰撞体相互嵌入。 2. 在 Update中修改位置,与物理更新冲突。3. 质量(Mass)差异过大且迭代次数不足。 | 1. 在Scene视图中检查初始位置,确保没有重叠。 2. 确保对Rigidbody的位置/速度修改在 FixedUpdate中进行。3. 适当增大Rigidbody的 Solver Iterations(求解器迭代次数,默认6),或调整质量比。 |
| 高速物体穿透 | 碰撞检测模式为Discrete。 | 将高速物体的Rigidbody的Collision Detection改为Continuous或Continuous Dynamic。 |
| 物体运动不流畅,有卡顿感 | 1. Rigidbody没有开启Interpolation。2. Fixed Timestep设置过大,或机器性能不足导致物理帧率不稳。 | 1. 为运动物体Rigidbody设置Interpolation为Interpolate。2. 尝试稍微减小 Fixed Timestep(如0.016),并优化代码性能。 |
| 施加力(AddForce)没反应 | 1. 力的大小太小。 2. 质量(Mass)太大。 3. 阻力(Drag)极大。 4. 刚体是 Kinematic(运动学)的。 | 1. 增大力的数值,或使用ForceMode.Impulse。2. 检查并减小Mass(默认1,可能被误设为1000)。 3. 检查Drag值。 4. 取消勾选 Is Kinematic。 |
| 碰撞事件(OnCollisionEnter)不触发 | 1. 双方都是触发器(Is Trigger)。 2. 至少一方没有Rigidbody。 3. 脚本未挂载,或方法名拼写错误。 4. 碰撞发生在同一帧物体被销毁或禁用。 | 1. 常规碰撞需要双方Is Trigger为false。2. 确保至少一方有Rigidbody。 3. 检查脚本和方法名(大小写敏感)。 4. 确保事件检测代码在物体存活时执行。 |
4.2 实用调试技巧
可视化调试是王道:在Scene视图的右上角,点击Gizmos下拉菜单,确保
Colliders是勾选状态。这样你就能在场景中清晰地看到所有碰撞体的绿色线框。对于触发器,线框是红色的。这是最直观的检查碰撞体形状、位置和是否重叠的方法。使用
Debug.DrawRay和Debug.DrawLine:在代码中临时绘制射线或线段,可以帮助你理解碰撞检测的范围和方向。void Update() { // 绘制一条从当前位置向前方延伸5单位的红线 Debug.DrawRay(transform.position, transform.forward * 5, Color.red); }利用
Physics Debugger(Unity 2022 LTS及以上):这是一个强大的内置工具。通过Window > Analysis > Physics Debugger打开。它可以实时显示物理世界的状态,包括碰撞体、接触点、刚体速度向量等,对于复杂物理问题的调试 invaluable。检查物理材质:有时候摩擦力或弹性不对劲,别忘了检查Collider上挂载的物理材质(Physics Material)是否正确,以及材质本身的参数是否设置合理。一个常见的错误是误将高弹性材质用在了不该用的地方,导致物体蹦蹦跳跳停不下来。
关注性能分析器:如果游戏在有很多物理物体时变卡,打开
Window > Analysis > Profiler,查看Physics和Physics2D所占用的CPU时间。如果异常高,检查是否有很多刚体从未进入睡眠(考虑设置Sleeping Mode),或者是否不必要地使用了Continuous Dynamic碰撞检测。