1. 项目概述:从“自由落体”到“真实交互”的必经之路
在Unity的世界里,让一个物体从空中掉下来,大概是每个开发者最早接触的物理模拟之一。听起来简单,不就是给个重力吗?但当你真正动手,想让一个方块砸到地面后还能弹两下,或者让一堆小球互相碰撞、堆叠出逼真的物理效果时,问题就来了:为什么我的物体穿过了地面?为什么碰撞后速度变得诡异?为什么物理表现时好时坏?这些“坑”,几乎每个Unity开发者都踩过,而解决它们的关键,就在于对Rigidbody(刚体)组件的透彻理解。
这个项目标题“Unity刚体Rigidbody实战:5分钟搞定物体自由落体与碰撞检测(附避坑指南)”,精准地戳中了从入门到进阶的痛点。它承诺的不仅是“实现”,更是“避坑”。对于新手,这意味着能快速搭建一个可运行的物理demo,建立信心;对于有一定经验的开发者,这意味着能系统性地排查那些隐藏在简单操作背后的复杂问题,比如碰撞矩阵的配置、物理材质的设置、刚体属性的细微差别对性能的影响等。Rigidbody是Unity物理引擎的基石,它赋予游戏对象模拟真实世界物理行为的能力——质量、阻力、重力、碰撞响应。而“自由落体与碰撞检测”则是这块基石上最经典、也最考验基础的两个应用场景。
接下来,我将以一个从业多年的视角,带你不仅“搞定”这个5分钟的基础操作,更深入拆解其背后的每一个参数、每一种设置,并附上我踩过无数坑才总结出的实战指南。我们会从最核心的设计思路开始,一步步拆解到代码实现和问题排查,确保你不仅能复现,更能理解为什么这么做,以及如何应对各种意外情况。
2. 核心思路与组件选型:为什么是Rigidbody+Collider?
在Unity中实现物理交互,一个最经典且必须的组合就是Rigidbody(刚体)加Collider(碰撞器)。这个组合的分工非常明确,理解这一点是避免后续一切混乱的基础。
Collider(碰撞器):它定义了游戏对象的“物理形状”。你可以把它想象成一个不可见的、坚硬的“外壳”。这个外壳告诉物理引擎:“我的物体占这么大一块空间,形状是这样的(可能是盒子、球体、胶囊体,或者更复杂的网格)。”但仅仅有形状是不够的,这个外壳本身是“静态”的,它不会对力产生反应,也不会主动移动。它只负责回答一个问题:“我有没有和别的‘外壳’碰到一起?”
Rigidbody(刚体):这才是让物体“活”起来的组件。它赋予了对象物理属性,如质量(Mass)、阻力(Drag)、角阻力(Angular Drag),并使其受到物理引擎力的影响,最典型的就是重力。更重要的是,它负责处理“碰撞响应”。当两个都带有Rigidbody的Collider发生碰撞时,物理引擎会根据它们的质量、速度、碰撞角度等,计算出碰撞后的速度、旋转变化,从而实现反弹、滑动、滚动等效果。
所以,回到我们的“自由落体”场景。要让一个物体下落,它必须受到重力。在Unity中,重力是一个全局的力场(在Edit -> Project Settings -> Physics中设置),但只有添加了Rigidbody组件的对象才会受到这个力场的影响。同时,要检测它是否“碰到”地面,它和地面都必须有Collider来定义彼此的边界。而碰撞发生后,物体是停下来还是弹起来,则由Rigidbody的属性和碰撞双方的物理材质共同决定。
注意:一个常见的误解是,认为移动的物体才需要
Rigidbody。实际上,对于静止的、作为碰撞边界的地面或墙壁,通常只需要Collider,而不需要Rigidbody。这种物体在物理引擎中被视为“静态碰撞体”(Static Collider),它无限重,不会因碰撞而移动,但能有效地阻挡和反弹其他动态刚体。如果你给地面也加了Rigidbody,它就会变成一个“动态刚体”,可能会被掉落的物体砸得微微移动,这通常不是我们想要的效果。
方案选型考量:
- 动态刚体(Dynamic Rigidbody):这是我们下落物体的标准选择。
Is Kinematic(是否为运动学)属性为false。它完全受物理引擎控制(重力、力、碰撞)。 - 静态碰撞体(Static Collider):这是我们地面的标准选择。只有
Collider,没有Rigidbody。性能最优,适用于永远不会移动的环境。 - 运动学刚体(Kinematic Rigidbody):将
Rigidbody的Is Kinematic设为true。此时,物理引擎不会用力和碰撞来驱动它,但它可以通过脚本直接变换位置(Transform)来移动,并且能推动其他动态刚体。它适用于由玩家直接控制(如角色控制器初期方案)、或者需要复杂脚本动画但又需要碰撞响应的物体。在我们的自由落体示例中不适用。
明确了“动态刚体下落,静态碰撞体接地”这个核心组合后,我们就能避免很多初级错误,比如物体不下落(没加Rigidbody)或者碰撞没反应(没加Collider)。
3. 环境准备与基础场景搭建
理论清晰后,我们开始动手。这个过程确实可以在5分钟内完成,但每一步的设置都关乎最终效果的稳定性和真实性。
3.1 创建基础场景与对象
- 打开Unity,创建一个新项目(3D核心模板即可)。
- 在Hierarchy面板右键,创建两个3D Object:一个
Cube(改名为FallingObject),一个Plane(改名为Ground)。Plane默认就是一个很大的平面,非常适合作为地面。 - 调整
FallingObject的位置,将其Y轴坐标设为5左右,让它悬在空中。 - 调整
Ground的位置和旋转,确保它水平放置(Rotation为0,0,0)。
3.2 添加物理组件
- 为地面(Ground)添加碰撞器:选中
Ground,你会在Inspector面板看到它自带一个Mesh Collider。对于简单的Plane,使用Mesh Collider没问题,但对于性能要求高的场景,更推荐用Box Collider。我们可以点击Mesh Collider组件右上角的齿轮图标,选择“Remove Component”移除它,然后点击“Add Component”,搜索并添加Box Collider。你会发现Box Collider完美贴合了平面的形状,且计算效率更高。 - 为下落物体(FallingObject)添加刚体和碰撞器:
- 选中
FallingObject,点击“Add Component”,搜索并添加Rigidbody。 - 同时,确保它有一个碰撞器。
Cube默认带有一个Box Collider,这正合适,我们保留它即可。
- 选中
现在,如果你点击运行,就会看到立方体直接落下,砸在平面上,然后可能轻微弹起或滑动一下,最终静止。一个最基本的自由落体与碰撞检测已经完成了!但这只是开始,效果很粗糙。我们接下来要深入每一个组件,进行精细化调整。
3.3 组件参数初解与常见坑点
Rigidbody组件关键参数:Mass(质量):默认1。质量影响惯性(改变运动状态的难易程度)和碰撞时的动量交换。一个质量很小的物体撞上一个质量很大的静态物体,几乎不会让大物体移动。注意:质量不是重量,在Unity的物理系统中,它没有单位。保持合理的相对比例更重要(比如,一个箱子质量是10,一个球质量是1)。Drag(阻力) &Angular Drag(角阻力):模拟空气(或介质)阻力。Drag影响直线运动速度的衰减,Angular Drag影响旋转速度的衰减。值越大,物体停下来越快。对于从高空落下的物体,通常需要一点Drag(比如0.1)来防止它无休止地滑动。Use Gravity(使用重力):默认勾选。如果取消,物体将不受重力影响。这是新手第一个坑:物体悬空不动,请先检查此项是否勾选!Is Kinematic(是否为运动学):如前所述,非特殊需求保持false。Interpolate(插值):默认为None。当刚体运动很快时,可能会在渲染帧之间“穿越”薄物体。如果发现碰撞检测不可靠(穿透),可以尝试将其设置为Interpolate(根据物理计算插值平滑变换)或Extrapolate(根据上一帧速度预测变换)。这能显著改善高速运动物体的视觉平滑度和碰撞可靠性。
Collider组件关键参数:Is Trigger(是否为触发器):如果勾选,该碰撞器将不再产生物理碰撞效果(即物体可以穿过),但会触发OnTriggerEnter等事件。第二个坑:如果你的物体直接穿过地面,请检查地面和下落物体的Collider,确保Is Trigger都没有被误勾选!Material(物理材质):这是实现弹性、摩擦力的关键,我们稍后详细讲。
4. 实现自由落体与基础碰撞响应
基础场景跑通后,我们来实现一个更可控、更典型的自由落体示例。比如,我们想让物体从指定高度落下,并在碰撞时输出日志,甚至根据碰撞力度改变颜色。
4.1 创建控制脚本
在Project面板右键,Create -> C# Script,命名为FallingObjectController。双击用编辑器打开,编写如下代码:
using UnityEngine; public class FallingObjectController : MonoBehaviour { private Rigidbody rb; private Renderer objectRenderer; // 用于改变颜色 public float dropHeight = 10f; // 初始下落高度 public Color collisionColor = Color.red; // 碰撞后颜色 private Color originalColor; // 原始颜色 void Start() { // 获取组件引用 rb = GetComponent<Rigidbody>(); objectRenderer = GetComponent<Renderer>(); if (objectRenderer != null) { originalColor = objectRenderer.material.color; } // 设置初始位置 ResetPosition(); } void ResetPosition() { // 将物体移动到指定高度,并重置速度和旋转 transform.position = new Vector3(0, dropHeight, 0); if (rb != null) { rb.velocity = Vector3.zero; // 清零速度 rb.angularVelocity = Vector3.zero; // 清零角速度 rb.Sleep(); // 让刚体“睡眠”,节省性能,直到下次受力唤醒 } // 恢复颜色 if (objectRenderer != null) { objectRenderer.material.color = originalColor; } } // 当碰撞发生时调用(非触发器碰撞) void OnCollisionEnter(Collision collision) { // 打印碰撞信息 Debug.Log(gameObject.name + " 碰撞到了: " + collision.gameObject.name); Debug.Log("相对速度: " + collision.relativeVelocity.magnitude); Debug.Log("接触点数量: " + collision.contactCount); // 根据碰撞力度改变颜色(力度越大,颜色越红) float impactStrength = Mathf.Clamp01(collision.relativeVelocity.magnitude / 10f); if (objectRenderer != null) { objectRenderer.material.color = Color.Lerp(originalColor, collisionColor, impactStrength); } // 示例:如果碰撞力度很大,3秒后重置位置 if (collision.relativeVelocity.magnitude > 5f) { Invoke(nameof(ResetPosition), 3f); } } // 提供一个在游戏运行时手动重置的方法(可用于测试) void Update() { if (Input.GetKeyDown(KeyCode.R)) { ResetPosition(); } } }将脚本拖拽到FallingObject游戏对象上。运行游戏,物体会从10个单位高度落下,碰撞地面时Console会输出信息,物体颜色会根据碰撞力度变红,强烈碰撞后3秒物体会重置到空中。
4.2 关键API与事件解析
OnCollisionEnter(Collision collision):这是最常用的碰撞检测事件。当非触发器碰撞器发生接触的那一帧被调用。Collision参数包含了丰富的碰撞信息:collision.gameObject:与之碰撞的另一个物体。collision.relativeVelocity:碰撞时的相对速度向量,其大小(magnitude)常用来衡量碰撞力度。collision.contacts:一个ContactPoint数组,包含了所有接触点的位置、法线等信息。对于简单形状通常只有一个接触点,复杂碰撞可能有多个。
OnCollisionStay和OnCollisionExit:分别在碰撞持续期间每帧调用,和碰撞分离的那一帧调用。Rigidbody.Sleep():这是一个重要的性能优化方法。当一个刚体静止一段时间后,物理引擎会使其“睡眠”,不再进行物理计算,直到有新的力作用其上。手动调用Sleep()可以立即让其进入睡眠状态。
实操心得:在
Start或初始化时,对静止的刚体调用rb.Sleep()是个好习惯。对于频繁重置位置的物体(比如掉落的道具),在重置位置和速度后调用Sleep(),可以避免它在空中就因为微小的数值误差或上一帧的残余速度而“抖动”,直到它真正开始下落时才被重力唤醒。
5. 高级碰撞调控:物理材质(Physic Material)详解
默认的碰撞效果(有点像硬塑料块撞到硬地面)往往不符合需求。我们可能需要橡皮球般的弹性,或者冰面般的低摩擦力。这时就需要Physic Material(物理材质)。
5.1 创建与配置物理材质
- 在Project面板右键,Create -> Physic Material,命名为
BouncyBall。 - 选中这个材质,Inspector面板会出现以下核心属性:
Dynamic Friction(动摩擦系数) &Static Friction(静摩擦系数):模拟摩擦力。0表示无摩擦(如冰面),1表示极大摩擦(如橡胶)。通常两者设为相同值即可。Bounciness(弹性系数):0表示无弹性(完全非弹性碰撞,如粘土),1表示完全弹性(理想情况,无能量损失)。注意:弹性效果取决于碰撞双方,取两者Bounciness的平均值或最大值(取决于Bounce Combine模式)。Friction Combine&Bounce Combine(摩擦/弹性组合模式):定义当两个物体碰撞时,如何组合各自的摩擦/弹性系数。Average(平均):常用模式。(A的系数 + B的系数)/ 2。Minimum(取小):使用两者中较小的值。Maximum(取大):使用两者中较大的值。Multiply(相乘):两者系数相乘,通常会导致极小的值。
5.2 应用物理材质并测试
- 将创建的
BouncyBall物理材质,拖拽到FallingObject的Box Collider组件的Material属性槽中。 - 将
BouncyBall的Bounciness设置为0.8,Friction都设置为0.1。 - 我们也可以为地面创建一个物理材质
HardGround,Bounciness设为0.1,Friction设为0.8,并赋给地面的Box Collider。 - 运行游戏。现在立方体落下后,会弹跳得更高,并且滑动距离更远,更像一个弹力球落在粗糙地面上。
5.3 组合模式的实际影响
这是一个极易被忽略但至关重要的设置。假设球(Bounciness=0.9)落在水泥地(Bounciness=0.1)上。
- 如果组合模式是
Average,则有效弹性为(0.9+0.1)/2 = 0.5,球会弹起,但不高。 - 如果组合模式是
Maximum,则有效弹性为max(0.9,0.1) = 0.9,球会弹得很高,仿佛地面也很有弹性。 - 如果组合模式是
Minimum,则有效弹性为min(0.9,0.1) = 0.1,球几乎弹不起来。
避坑指南:如果你的物体弹性表现和预期不符,在检查了各自材质弹性值后,务必检查
Bounce Combine模式!对于大多数需要直观控制的情景,Average模式是最符合直觉的。Maximum模式常用于希望某个物体(如超级弹力球)无论撞到什么都能弹得很高的场景。
6. 性能优化与稳定性调优
物理计算是性能消耗大户,不当的设置会导致卡顿甚至物理引擎崩溃。以下是几个关键的调优点。
6.1 刚体睡眠与唤醒
如前所述,物理引擎会自动让静止的刚体睡眠。但有时会出现“抖动不休”无法睡眠的情况,导致不必要的性能消耗。常见原因及解决:
- 原因1:连续微小的碰撞或力。检查场景中是否有持续作用的微小力(如风力区域)、或碰撞体交叠。
- 原因2:
Collider形状过于复杂。对于运动物体,避免使用高精度的Mesh Collider。优先使用Box、Sphere、Capsule等基本碰撞体,或它们的组合(Compound Colliders)。如果必须用网格,考虑使用简化的凸包(Mesh Collider勾选Convex),但注意凸包碰撞计算量仍大于基本体。 - 原因3:质量(Mass)过小。质量极小的物体会对微小的力非常敏感,难以稳定。确保质量在一个合理的范围内(比如0.1到100之间),避免使用0或极小的值。
6.2 碰撞体优化策略
- 层级简化(Layer Collision Matrix):不是所有物体都需要互相碰撞。通过Edit -> Project Settings -> Physics,打开碰撞矩阵(Collision Matrix),可以取消勾选某些层级之间的碰撞检测。例如,将大量只作为背景装饰的物体放在“Decor”层,并取消该层与“Player”、“Enemy”等层的碰撞,能大幅减少物理计算量。
- 使用触发器(Trigger)替代物理碰撞:如果只需要知道两个物体是否重叠,而不需要真实的物理推力(比如拾取物品、进入区域),那么使用触发器(勾选
Is Trigger)是更高效的选择,因为它省去了复杂的碰撞响应计算。 - 调整物理更新频率:在Edit -> Project Settings -> Time中,
Fixed Timestep决定了物理更新的时间间隔(默认0.02秒,即50Hz)。降低此值(如0.04秒)可以提高性能但降低物理精度;提高此值(如0.016秒)可以增加精度但加重负担。通常保持默认即可,除非有特殊的高精度或性能需求。
6.3 解决“抖动”与“穿透”问题
- 抖动(Jitter):通常发生在两个质量、速度相近的物体堆叠或碰撞时,物理引擎在每一帧都无法稳定求解它们的位置,导致高频微震。
- 解决方案:增加
Fixed Timestep(提高计算精度),或降低Time设置中的Maximum Allowed Timestep(防止单帧物理计算时间过长)。更根本的方法是优化碰撞形状、调整质量比、或者对堆叠物体使用关节(Joint)约束而非纯粹靠碰撞。
- 解决方案:增加
- 穿透(Penetration):物体部分或全部穿过了另一个碰撞体。
- 解决方案:这是高速移动物体最常见的问题。首先,尝试为高速刚体启用
Interpolate或Extrapolate。其次,确保Collider的尺寸略小于视觉网格(Mesh),为物理计算留出容错空间。最后,可以考虑使用连续碰撞检测(CCD)。- 连续碰撞检测(Continuous Collision Detection):在
Rigidbody组件中,将Collision Detection从默认的Discrete(离散)改为Continuous(连续)或Continuous Dynamic(连续动态)。这会显著增加计算开销,但能有效防止高速子弹、小球等物体穿透薄墙。仅对少数高速运动的物体启用此功能。
- 连续碰撞检测(Continuous Collision Detection):在
- 解决方案:这是高速移动物体最常见的问题。首先,尝试为高速刚体启用
7. 常见问题排查与实战技巧实录
即使按照步骤操作,奇怪的问题依然可能出现。这里记录了一些典型问题及其排查思路。
7.1 问题清单与速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 物体静止不动,不下落 | 1.Rigidbody组件未添加。2. Use Gravity未勾选。3. 物体被脚本锁定了位置(如 rb.isKinematic = true或脚本中每帧设置position)。 | 1. 检查Inspector面板是否有Rigidbody。2. 检查 Rigidbody中Use Gravity是否勾选。3. 检查所有附加脚本,是否在 Update中直接修改transform.position。应使用rb.AddForce或修改rb.velocity来移动物理物体。 |
| 物体直接穿过地面或其他物体 | 1. 地面或物体缺少Collider。2. 地面或物体的 Collider被勾选为Is Trigger。3. 物体速度过快(穿透)。 4. 碰撞双方层级在碰撞矩阵中被禁用。 | 1. 确认双方都有Collider组件。2. 检查双方 Collider的Is Trigger属性。3. 为高速物体启用 Interpolate或Continuous Collision Detection。4. 检查Physics设置中的Layer Collision Matrix。 |
| 碰撞后物体行为诡异(如疯狂旋转、飞走) | 1. 质量(Mass)设置不合理(如过大或过小)。2. 碰撞体形状复杂且未设置为凸包( Convex)。3. 物理材质( Physic Material)的摩擦/弹性系数极端或组合模式异常。4. 多个碰撞体意外重叠。 | 1. 调整Mass到合理范围(0.1-100)。2. 对于 Mesh Collider,尝试勾选Convex,或改用基本碰撞体组合。3. 检查并调整物理材质属性,将 Bounce Combine和Friction Combine设为Average。4. 在Scene视图中开启Gizmos显示碰撞体,检查是否有意外交叠。 |
| 物理效果卡顿或不稳定 | 1. 场景中动态刚体数量过多。 2. 使用了高精度 Mesh Collider且未勾选Convex。3. Fixed Timestep设置过低,或单帧物理计算超时。 | 1. 对静止物体使用静态碰撞体(无Rigidbody)。对大量小物体考虑使用简化碰撞体或触发器。2. 对所有运动的 Mesh Collider启用Convex,或替换为基本体。3. 适当调高 Fixed Timestep(如0.033s),或降低Maximum Allowed Timestep。 |
OnCollisionEnter事件不触发 | 1. 碰撞双方至少一方是触发器(Is Trigger)。触发器事件是OnTriggerEnter。2. 脚本未挂载在发生碰撞的物体上,或脚本被禁用。 3. 碰撞发生在刚体睡眠时(某些旧版本可能不触发)。 | 1. 确认是否需要物理碰撞,不需要则改用OnTriggerEnter,需要则取消Is Trigger。2. 检查脚本挂载和启用状态。 3. 尝试在脚本中禁用刚体睡眠( rb.sleepMode = RigidbodySleepMode.NeverSleep)进行测试,但不推荐长期使用。 |
7.2 独家避坑技巧
- “视觉网格”与“碰撞体”分离:对于复杂的模型,不要直接使用其网格渲染器(MeshRenderer)的网格作为
Mesh Collider。最好创建一个简单的子物体(比如一个Cube或几个基本形状的组合),挂上基本的Collider,用这个子物体代表物理轮廓。这能极大提升性能和稳定性。 - 善用“刚体约束(Constraints)”:在
Rigidbody组件底部,可以冻结(Freeze)某个位置或旋转轴。例如,一个2D横版游戏的角色,你可能需要冻结Z轴位置和X、Y轴旋转,只允许在XY平面移动和绕Z轴旋转。这能防止物体意外翻倒或掉出平面。 - 调试利器:物理调试视图:在Scene视图左上角的Gizmos下拉菜单中,可以开启
Colliders的显示。你还可以在Game视图叠加物理调试信息(需要编写简单代码或使用第三方工具),实时观察碰撞体、接触点、力向量等,这对于排查复杂物理问题至关重要。 - 关于
Time.fixedDeltaTime:所有在FixedUpdate中进行的物理相关操作(如AddForce)都是与这个固定时间步长相关的。如果你在Update中读取速度(rb.velocity),由于Update帧率可变,而物理更新固定,可能会读到过时或插值后的速度。对于需要精确物理状态判断的逻辑,尽量放在FixedUpdate中。
8. 从基础到应用:扩展场景示例
掌握了核心原理和避坑技巧后,我们可以尝试更复杂的场景,将刚体和碰撞检测用得更活。
8.1 场景:多物体堆叠与稳定性
创建一个场景,地面之上有多个不同形状(Cube, Sphere)和质量的物体。目标是让它们落下后能稳定堆叠。
- 挑战:物体容易滑落、抖动或倒塌。
- 解决方案:
- 调整物理材质:适当增加摩擦系数(
Friction),减少弹性(Bounciness),比如都设为0.5左右。 - 优化质量比:底部的物体质量设置得大一些(如10),上面的物体质量小一些(如1),增加稳定性。
- 使用
Interpolate:为所有动态刚体启用Interpolate,平滑运动,减少抖动。 - 微调
Fixed Timestep:如果堆叠非常不稳定,可以尝试稍微减小Fixed Timestep(如0.016),提高物理计算精度,但需注意性能。
- 调整物理材质:适当增加摩擦系数(
8.2 场景:发射小球并计算碰撞次数
编写脚本,按空格键从摄像机前方发射一个小球(Sphere),并统计它直到静止共发生了多少次碰撞。
using UnityEngine; public class BallLauncher : MonoBehaviour { public GameObject ballPrefab; public float launchForce = 20f; private int totalCollisionCount = 0; void Update() { if (Input.GetKeyDown(KeyCode.Space)) { LaunchBall(); } } void LaunchBall() { totalCollisionCount = 0; GameObject ball = Instantiate(ballPrefab, transform.position, Quaternion.identity); Rigidbody rb = ball.GetComponent<Rigidbody>(); rb.AddForce(transform.forward * launchForce, ForceMode.Impulse); // 为小球添加一个临时脚本来计数 BallCollisionCounter counter = ball.AddComponent<BallCollisionCounter>(); counter.onCollisionLogged = (count) => { totalCollisionCount = count; Debug.Log("小球总计碰撞次数: " + totalCollisionCount); }; } } // 临时附加的计数脚本 public class BallCollisionCounter : MonoBehaviour { private int collisionCount = 0; public System.Action<int> onCollisionLogged; void OnCollisionEnter(Collision collision) { collisionCount++; Debug.Log($"碰撞 #{collisionCount} with {collision.gameObject.name}"); // 可以在这里判断速度,如果速度很小,认为即将静止,报告总数 if (GetComponent<Rigidbody>().velocity.magnitude < 0.1f) { onCollisionLogged?.Invoke(collisionCount); } } }这个例子综合运用了刚体受力(AddForce)、碰撞事件监听和简单的物体生成与销毁管理。
8.3 场景:实现一个简单的“弹簧床”效果
创建一个有弹性的平台,物体落在上面会被高高弹起。
- 创建一个新的Cube作为弹簧床,为其添加
Rigidbody,但勾选Is Kinematic(因为我们可能想用脚本控制其上下运动,而不是完全物理驱动)。 - 为这个Cube添加一个脚本,在
OnCollisionEnter中,根据碰撞力度,给碰撞到的物体(collision.rigidbody)施加一个向上的力(AddForce)。 - 或者,更物理的方法是:为弹簧床的碰撞体赋予一个高弹性(如0.9)的物理材质,并将其
Rigidbody的Mass设置得非常大(如1000),这样当质量小的物体撞上时,几乎所有的动能都会转化为弹性势能再返还,实现高弹跳。同时,可以结合脚本在碰撞时播放一个压缩再恢复的动画,增强视觉效果。
通过以上从基础到进阶的拆解,你会发现,Unity的刚体系统看似简单,但门道很深。每一个参数背后都对应着物理模拟的一个方面。理解它们,不仅能帮你实现“物体下落”这种基础功能,更能让你在开发复杂的物理游戏(如解谜、赛车、沙盒)时游刃有余。记住,遇到奇怪的物理现象,不要慌,按照“组件检查(Rigidbody/Collider)-> 属性核对(重力、触发器、材质)-> 性能与稳定性调优(睡眠、穿透、抖动)”的流程一步步排查,大部分问题都能迎刃而解。