Unity 物理引擎:刚体、碰撞器与关节
Unity 物理引擎完全指南:刚体、碰撞器与关节
在游戏开发中,物理模拟决定了物体如何移动、碰撞和交互。Unity 内置的 NVIDIA PhysX 引擎提供了强大而高效的工具,让开发者无需编写复杂的数学公式即可实现真实的物理行为。本教程面向零基础初学者,系统讲解 Unity 物理引擎的核心三要素:刚体(Rigidbody)、碰撞器(Collider) 和 关节(Joint)。你将学会使用它们构建可控的物理世界,并掌握性能优化技巧。
一、刚体:让物体接受物理法则
刚体是赋予 GameObject 物理属性的核心组件。没有刚体的物体是静态的,不会受重力或力影响。
1.1 刚体关键属性
| 属性 | 功能说明 | 常用场景 |
|---|---|---|
| Mass | 质量(单位任意,相对值)。质量越大,推动它需要的力越大。 | 轻重物体差异化表现 |
| Drag | 移动阻力。数值越高,物体线性减速越快。 | 模拟空气阻力 |
| Angular Drag | 旋转阻力。控制角速度衰减。 | 让旋转的物体慢慢停下 |
| Use Gravity | 是否受重力影响。关闭后物体浮空。 | 太空环境、飞行道具 |
| Is Kinematic | 运动学模式。开启后物体不受物理力影响,仅通过 Transform 或脚本移动,但仍能碰撞其他物体。 | 移动平台、玩家角色控制 |
| Interpolate | 运动平滑模式(None / Interpolate / Extrapolate)。消除高速物体画面抖动。 | 快速移动的子弹 |
| Collision Detection | 碰撞检测精度:Discrete(离散)、Continuous(连续)、Continuous Dynamic(连续动态)。 | 防止高速物体穿透 |
1.2 刚体运动控制方式
刚体上的 Rigidbody 组件是控制运动的入口。强烈建议通过刚体接口而非直接修改 Transform 来移动物体,否则会干扰物理状态。
- AddForce:施加持续力,模拟推力或拉力,适用于自然加速度。
- velocity:直接设置速度,适用于瞬间达到目标速度(如弹射)。
- MovePosition:向目标位置移动,遵守碰撞规则,常用于 kinematic 物体或需要穿墙停止的情况。
代码示例:推动箱子
using UnityEngine;
public class PushBox : MonoBehaviour
{
public Rigidbody rb;
public float forceMagnitude = 10f;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
if (Input.GetKey(KeyCode.W))
{
// 在世界坐标前方施加力
rb.AddForce(Vector3.forward * forceMagnitude);
}
}
}
关键提示:所有物理相关操作必须在
FixedUpdate中执行,以保证与物理步长同步。
1.3 刚体休眠机制
为优化性能,PhysX 会让低速且无外力作用的刚体进入“休眠”。休眠后的物体不会进行物理计算,直到再次被碰撞或施力唤醒。可通过 Rigidbody.Sleep() 强制休眠,或设置 Sleep Threshold 调整灵敏度。
二、碰撞器:定义物体的物理形状
碰撞器是物体在物理世界中“碰撞体积”的描边。没有碰撞器,刚体之间会直接穿过。
2.1 常见碰撞器类型
| 碰撞器类型 | 特点 | 适合用途 |
|---|---|---|
| Box Collider | 长方体,性能最优 | 墙壁、箱子、触发区域 |
| Sphere Collider | 球体,滚动天然稳定 | 球、轮子、滚动道具 |
| Capsule Collider | 胶囊形,底部平滑 | 角色控制器、树干 |
| Mesh Collider | 基于网格精确形状,性能开销大 | 静态环境、复杂地形 |
| Terrain Collider | 专用于地形对象,自动匹配高度图 | 自然场景地面 |
| Wheel Collider | 专为车辆轮胎设计,内置悬挂与摩擦力 | 车辆系统 |
2.2 触发器与物理碰撞
碰撞器上的 Is Trigger 复选框决定了它的行为:
- 取消勾选(默认):产生物理碰撞,物体会被阻挡。可使用
OnCollisionEnter、OnCollisionStay、OnCollisionExit回调。 - 勾选 Is Trigger:不阻挡物体,仅用于检测“进入范围”。使用
OnTriggerEnter、OnTriggerStay、OnTriggerExit回调。
触发器常用于实现检查点、拾取道具、伤害区域等非阻挡性检测。
2.3 碰撞矩阵与层级屏蔽
在项目设置 Physics Settings 中可以通过碰撞矩阵控制哪些层之间会发生碰撞,剔除不必要的计算。例如,将“玩家子弹”层与“敌人”层设为相互碰撞,而“玩家子弹”与“玩家自身”层则屏蔽。合理设置能显著降低物理开销。
2.4 复合碰撞器与物理材质
- 复合碰撞器:为一个对象添加多个不同形状的碰撞器(例如角色使用胶囊体+球形手脚),精确拟合轮廓,但比单个 Mesh Collider 高效。
- 物理材质 (Physic Material):赋予碰撞器表面属性
Dynamic Friction(动摩擦)、Static Friction(静摩擦)、Bounciness(弹性)。通过创建 Physic Material 资源并拖入碰撞器的Material槽位生效。
2.5 碰撞事件代码示例
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Player"))
{
Debug.Log("被玩家碰撞了!");
}
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Coin"))
{
Destroy(other.gameObject);
// 加分逻辑
}
}
注意:触发回调函数中的参数是
Collider,物理碰撞回调中是Collision,后者包含更多信息(如接触点、相对速度)。
三、关节:连接两个物体的物理约束
关节组件可以将两个刚体以特定方式连接,模拟真实世界的机械结构。所有关节都需要至少一方拥有刚体组件。
3.1 常用关节类型速查
| 关节 | 功能 | 经典用例 |
|---|---|---|
| Fixed Joint | 完全固定两个物体,像粘合在一起 | 拾取物品、碎片粘附 |
| Hinge Joint | 绕单一轴旋转(如门铰) | 门、钟摆、杠杆 |
| Spring Joint | 像弹簧一样弹性连接 | 弹簧绳、软性连接 |
| Character Joint | 为人形角色设计的复杂关节,模拟骨骼约束 | 布娃娃系统 |
| Configurable Joint | 可定制程度最高,自由设置线性与角度限制 | 高级机械臂、自定义约束 |
3.2 Hinge Joint 深度解析
铰链关节是最常用的旋转关节,关键属性:
- Axis:旋转轴(世界或自身坐标)。
- Use Limits:限制旋转角度,设置 Min/Max。
- Use Motor:驱动旋转,可设定目标速度与力。
- Use Spring:弹性恢复到目标角度。
- Break Force / Break Torque:超过设定阈值关节自动断裂。
示例:制作一扇自动关闭的门
// 挂在有HingeJoint的门上
public class AutoCloseDoor : MonoBehaviour
{
private HingeJoint hinge;
void Start() => hinge = GetComponent<HingeJoint>();
void OnTriggerExit(Collider other)
{
if (other.CompareTag("Player"))
{
JointMotor motor = hinge.motor;
motor.targetVelocity = -80; // 反向速度使之关闭
motor.force = 100;
hinge.motor = motor;
hinge.useMotor = true;
}
}
}
3.3 Spring Joint 应用
弹簧关节使两物体间保持动态弹性距离。调节 Spring(刚度)和 Damper(阻尼)创建柔韧的绳子或晃动效果。常用于:
- 悬挂的灯受撞击摇摆
- 牵引磁铁效果
3.4 关节的 Break Force 陷阱
Break Force 和 Break Torque 设为 Infinity 时关节永不破坏。当断裂时,关节组件会被自动移除,并调用 OnJointBreak(float breakForce) 回调。利用此特性可实现:
- 绳索断裂效果
- 可破坏的机械结构
提示:多个关节连接形成链时,物理稳定性会下降。尽量避免过长的关节链,必要时使用 Configurable Joint 实现单关节替代多关节。
四、性能优化与最佳实践
物理模拟可能成为性能瓶颈,务必遵守以下原则:
4.1 精简碰撞器数量与复杂度
- 静态环境尽量使用 Box/Sphere 等原型碰撞器组合,避免使用复杂 Mesh Collider。
- 对于必须使用 Mesh Collider 的地形,勾选
Convex限制为凸壳以加速计算(虽然形状会简化)。 - 为动态对象设置
Collision Detection为Continuous Speculative而非Continuous Dynamic,后者开销极大。
4.2 固定时间步长设置
Edit > Project Settings > Time > Fixed Timestep 决定了物理更新频率。默认 0.02 秒(50 Hz)。对于需要高精度物理的游戏(如竞技射击),可适当减小该值,但需注意 CPU 负荷。
4.3 巧用物理层与忽略碰撞
在代码中动态忽略特定物体间的碰撞:
Physics.IgnoreCollision(colliderA, colliderB, true);
或预设层矩阵,避免大量运行时判断。
4.4 休眠与运动学物体的平衡
- 大量静止刚体应允许它们自然休眠,不要频繁唤醒。
- 移动平台等反复运动的物体,勾选
Is Kinematic并由脚本控制,避免每帧物理计算。
4.5 关注 Rigidbody 数量
同场景激活的刚体数尽量控制在数百以内。如果确实需要成千上万个独立物理物体,考虑使用 ECS + Unity Physics 或转为特效动画模拟。
五、常见问题与排错
物体穿透地面/墙壁
- 确保两个物体都有 Collider(静态物体至少需要 Collider 才能碰撞,可以没有 Rigidbody)。
- 高速物体:将
Collision Detection设为 Continuous Dynamic(动态)或 Continuous Speculative(快速动态),并注意刚体的质量比不宜过大。
关节抖动或旋转异常
- 检查连接的两个物体是否都正确设置了 Rigidbody(非运动学)且质量差不过分悬殊。
- 适当提高
Solver Iterations(Project Settings > Physics > Default Solver Iterations),增加关节解算精度。
触发事件不触发
- 确认其中至少一方附有 Rigidbody(通常是移动的一方)。
- 确认碰撞矩阵中两层允许交互。
六、总结与进阶之路
通过掌握刚体、碰撞器和关节的配合使用,你已能构建出可靠的物理交互。接下来建议深入学习:
- Rigidbody 的 MovePosition 与插值 实现流畅的玩家移动。
- 可配置关节 打造自定义绳索、拉链等复杂约束。
- Physics.Raycast 与物理查询,实现无碰撞的检测。
- DOTS Physics 获得超高实体数量的物理表现。
物理引擎是世界规则的引擎,合理运用它能以极低的代码量实现令人信服的游戏体验。现在,打开 Unity 开始你的第一个物理实验吧。