【Unity基础详解】(6)Unity核心:物理系统
学习物理系统、碰撞器、触发器、刚体、角色控制器、几种控制移动的方式
目录
1.6.1 OnCollisionEnter(Collision collision)
1.6.2 OnCollisionStay(Collision collision)
1.6.3 OnCollisionExit(Collision collision)
4.3.1 CharacterController.SimpleMove
4.3.2 CharacterController.Move
Unity 中内置了一套完成的物理引擎,能够完成现实世界的近似模拟。而在 Unity 物理引擎中,刚体组件和碰撞体组件则是无法避开的,刚体组件是让物体产生物理行为的组件,而碰撞体组件则是让刚体与物体产生碰撞的组件。
1 碰撞器和触发器
为物体添加碰撞体组件后,该组件会默认阻挡其他刚体的运动。碰撞体用于定义物体的物理边界形状,虽然本身不可见(类似于空气墙的概念)。例如创建Cube对象时,系统会自动为其添加Box Collider组件。
在基本几何体中:
- 立方体默认配备Box Collider
- 球体自动带有Sphere Collider
- 胶囊体则拥有Capsule Collider
这些基础碰撞体具有最优的计算性能。通过组合多个碰撞体组件,可以构建更复杂的碰撞形状。
重要说明:要使碰撞生效,刚体必须绑定在被碰撞物体上,而碰撞体本身则不强制要求绑定刚体组件。
1.1 Box Collider

Box Collider是最基础的碰撞体类型,采用立方体外形设计。它广泛应用于游戏中的各类物体,如墙壁、门窗、平台等静态场景元素。此外,Box Collider也适用于角色躯干、载具外壳等动态物体,尤其适合为方形物体(如箱子)提供精确的碰撞检测。
|
参 数 |
含义 |
描述 |
|
Is Trigger |
触发器 |
勾选,则该碰撞体可用于触发事件,并被物理引擎忽略 |
|
Material |
材质 |
为碰撞体设置不同类型的材质 |
|
Center |
中心 |
碰撞体在对象局部坐标中的位置 |
|
Size |
大小 |
碰撞体在X、Y、Z方向上的大小 |
当勾选 Is Trigger 选项时,该对象在发生碰撞动作后将发送三种碰撞信息至脚本参数,分别为:OnTriggerEnter(进入触发)、OnTriggerExit(退出触发)和 OnTriggerStay(持续触发)。
Physics Material 用于设置物理材质属性,支持多种预设类型,包括冰面、金属、塑料和木材等材质选项。
1.2 Sphere Collider

Sphere Collider 是一种球体形状的碰撞组件。其三维尺寸只能按统一比例缩放,无法单独调整单个轴向的尺寸,具体参数如下表所示。
|
参 数 |
含义 |
描述 |
|
Is Trigger |
触发器 |
勾选,则该碰撞体可用于触发事件,并被物理引擎忽略 |
|
Material |
材质 |
为碰撞体设置不同类型的材质 |
|
Center |
中心 |
碰撞体在对象局部坐标中的位置 |
|
Radius |
半径 |
设置球形碰撞体的大小 |
当游戏对象的物理形状为球体时(如落石、乒乓球等),应使用球体碰撞体组件。
1.3 Capsule Collider

Capsule Collider由一个圆柱体和两个半球体组成,其半径和高度均可独立调节。该碰撞体适用于角色控制器,也可与其他不规则形状的碰撞体配合使用。通常会被添加至角色或NPC等游戏对象的碰撞属性中。
|
参 数 |
含义 |
描述 |
|
Is Trigger |
触发器 |
勾选,则该碰撞体可用于触发事件,并被物理引擎忽略 |
|
Material |
材质 |
为碰撞体设置不同类型的材质 |
|
Center |
中心 |
碰撞体在对象局部坐标中的位置 |
|
Radius |
半径 |
设置胶囊体形碰撞体的大小 |
|
Height |
局度 |
控制碰撞体中圆柱的高度 |
|
Direction |
方向 |
设置在对象的局部坐标中胶囊体的纵向所对应的坐标轴,默认是Y轴 |
1.4 Mesh Collider

Mesh Collider(网格碰撞体)根据Mesh形状产生碰撞体,比起 Box Collider、Sphere Collider和Capsule Collider,Mesh Collider更加精确,但会占用更多的系统资源。专门用于复杂网格所生成的模型。
|
参 数 |
含义 |
描述 |
|
Convex |
凸起 |
勾选,则Mesh Collider将会与其他的Mesh Collider发生碰撞 |
|
Material |
材质 |
为碰撞体设置不同类型的材质 |
|
Mesh |
网格 |
获取游戏对象的网格并将其作为碰撞体 |
1.5 Wheel Collider
Wheel Collider(车轮碰撞体)是一种针对地面车辆的特殊碰撞体,自带碰撞侦测、轮胎物理现象和轮胎模型,专门用于处理轮胎。

|
参 数 |
含义 |
描述 |
|
Mass |
质量 |
用于设置 Wheel Collider 的质量 |
|
Radius |
半径 |
用于设置碰撞体的半径大小 |
|
Wheel Damping Rate |
车轮减震率 |
用于设置碰撞体的减震率 |
|
Suspension Distance |
悬挂距离 |
该项用于设置碰撞体悬挂的最大伸长距离,按照局部坐标来计算, 悬挂总是通过其局部坐标的 Y 轴延伸向下 |
|
Center |
中心 |
用于设置碰撞体在对象局部坐标的中心 |
|
Suspension Spring |
悬挂弹簧 |
用于设置碰撞体通过添加弹簧和阻尼外力使得悬挂达到目标位置 |
|
Forward Friction |
向前摩擦力 |
当轮胎向前滚动时的摩擦力属性 |
|
Sideways Friction |
当轮胎侧向滚动时的摩擦力属性 |
|
|
Wheel Damping Rate |
车轮减震率 |
用于设置碰撞体的减震率 |
|
Wheel Damping Rate |
车轮减震率 |
用于设置碰撞体的减震率 |
1.6 碰撞检测
1.6.1 OnCollisionEnter(Collision collision)
触发时机:物体首次与其他物体发生碰撞时
参数说明:
collision.gameObject:碰撞对象
碰撞点、碰撞法线、接触点等碰撞信息
典型应用:
播放碰撞音效/动画
首次碰撞伤害计算
根据碰撞对象标签/层级执行特定逻辑
1.6.2 OnCollisionStay(Collision collision)
触发时机:碰撞持续期间每帧调用
参数说明:与OnCollisionEnter参数相同
典型应用:
持续伤害处理
摩擦力/滑动效果实现
碰撞状态持续检测
适用场景:需要持续作用的碰撞效果或状态维护
1.6.3 OnCollisionExit(Collision collision)
触发时机:碰撞关系解除时
参数说明:包含碰撞结束时的相关信息
典型应用:
特效终止
状态恢复
触发后续事件
适用场景:碰撞结束后的清理工作或事件触发
1.7 触发检测
Unity中的触发类回调(Trigger-based)是通过将碰撞体(Collider)设置为触发器(Trigger)来实现的。当碰撞体被设为触发器时,不会产生物理碰撞效果,而是通过触发事件来处理交互。系统提供了三个主要的触发回调方法:OnTriggerEnter、OnTriggerStay和OnTriggerExit,分别用于处理物体进入、停留和离开触发区域时的逻辑,适用于各种需要检测区域交互的场景。
1.7.1 OnTriggerEnter
- 在物体首次进入触发区域时调用
- 典型应用:触发任务、播放音效、拾取物品等一次性事件
1.7.2 OnTriggerExit
在物体离开触发区域时调用 典型应用:
- 结束持续效果(如停止伤害)
- 恢复原有状态(如解除减速)
- 终止特定交互行为
1.7.3 OnTriggerStay
在物体停留在触发区域内时每帧调用 典型应用:
- 持续伤害效果(如火焰或毒气区域)
- 持续状态影响(如减速、增益等)
- 需要持续检测的交互状态
1.8 碰撞器和触发器的异同
|
特性 |
碰撞器(Collider) |
触发器(Trigger) |
|
物理反应 |
产生物理碰撞(阻挡物体运动) |
无物理碰撞,仅触发事件 |
|
事件函数 |
OnCollisionEnter/Stay/Exit |
OnTriggerEnter/Stay/Exit |
|
配置方式 |
默认状态 |
需勾选Collider的Is Trigger选项 |
|
必要条件 |
至少一个物体带有Rigidbody |
至少一个物体带有Rigidbody |
2 Rigidbody刚体
Unity 提供了两种刚体组件:Rigidbody 和 Rigidbody2D。本文主要探讨前者。要让游戏对象具备真实的物理特性(如受重力影响),就需要为其添加 Rigidbody 组件,这是实现物理行为的基础组件。通过它,我们可以设置物体的质量、摩擦系数以及碰撞参数等常见物理属性。
从物理学的角度来看,刚体是一种理想模型:在外力作用下,物体能保持形状和尺寸不变,且内部各部分的相对位置始终恒定。
添加该组件的方法很简单:选中目标对象后,在 Inspector 面板中点击"Add Component"按钮,搜索"Rigidbody"即可完成添加。

2.1 Mass质量
设置物体的质量属性,默认值为1千克(kg)。根据物理原理,当物体质量为1kg时,施加9.8N的力即可抵消重力作用;若力值略大于9.8N,物体将产生向上的运动。
2.2 Drag阻力
设置物体的线性运动阻力,默认值为0(无阻力)。阻力方向始终与运动方向相反,数值越大则阻力越强,运动速度衰减越快。当阻力极大时,物体会瞬间停止运动。
2.3 Angular Drag角阻力
设置物体的旋转阻力,默认值为0.05。该阻力作用于物体的所有旋转方向,数值越大则旋转速度衰减越快。若设为0,物体在无重力环境下将持续旋转(无衰减)。
2.4 Use Gravity使用重力
控制物体是否受重力影响。选中时将模拟真实世界中的自由落体运动;未选中时则模拟无重力环境下的运动状态。
2.5 Is Kinematic是否遵循动力学
决定物体是否参与物理模拟。选中后,物体将不受质量、重力、阻力等物理参数影响,仅通过脚本或动画驱动。此选项可降低性能消耗,但需注意:
- 虽然不受物理模拟影响,仍可通过脚本移动其Transform来碰撞其他刚体
- 只对刚体产生碰撞影响
2.6 Interpolate插值
用于解决物理模拟与画面渲染的同步问题。当物体移动出现抖动时,建议调整此选项:
- Interpolate:基于前一帧数据进行平滑处理
- Extrapolate:基于下一帧预测数据进行平滑处理
2.7 Collision Detection碰撞检测
控制高速运动物体的碰撞检测方式:
- Discrete:离散检测(默认,性能最优)
- Continuous:连续检测(适用于被高速撞击的物体)
- Continuous Dynamic:动态连续检测(适用于高速运动的物体)
- Continuous Speculative:扫描式连续检测
2.8 Constraints约束条件
限制物体在特定方向上的移动或旋转自由度。默认不施加任何约束,由物理系统完全控制各轴向运动。

我们冻结了这扇门在 XYZ 轴上的移动以及 XZ 轴上的旋转。现在通过物体推动就能实现基本的门效果。如果需要单扇门推动效果(虽然使用物理关节实现会更简便)。
3 Character Controller
Character Controller是Unity中专门用于角色移动和碰撞处理的组件。相比基础的Rigidbody组件,它提供了更高级的控制方式,能够简化角色行走、跳跃等动作的实现流程。
核心功能
基础移动控制
- 提供
Move()函数实现精确位移- 通过
SimpleMove()自动处理重力效果- 使用
isGrounded属性检测地面接触状态
碰撞系统
- 自动处理环境碰撞(包括斜坡和楼梯)
- 支持多层碰撞检测
- 可自定义碰撞参数(半径、高度等)
物理特性
- 避免Rigidbody的物理副作用(如滑落斜坡)
- 保持移动稳定性
- 支持射线检测和触发器交互
适用场景
该组件特别适合第三人称游戏中的角色移动系统,包括:
- 基础位移(行走/奔跑)
- 跳跃动作
- 简单的环境交互
对于需要复杂物理模拟的场景,建议结合Rigidbody组件使用。Character Controller开箱即用,添加后无需额外配置Rigidbody即可实现完整的碰撞检测功能。

Slope Limit:斜坡角度上限,超过该角度角色无法攀爬。
Step Offset:台阶高度阈值(单位:米),仅当台阶低于该值时角色才能跨越。该值不可超过角色控制器高度。
Skin Width:碰撞体穿透深度,决定两个碰撞体间最大允许穿透距离。较大的值可减少抖动,过小可能导致角色卡住,建议设置为碰撞体半径的10%。
Min Move Distance:最小移动距离,通常设为0。适当调高可改善抖动现象。
- 地面检测:isGrounded()
- 受重力移动:SimpleMove()
- 不受重力移动:Move()
- 碰撞检测:OnControllerColliderHit(ControllerColliderHit hit)
4 物体移动大全
4.1 Transform
4.1.1 Transform.position
Transform.position是最基础的移动实现方式,其核心原理是逐帧直接更新物体的世界坐标位置。
直观可控:开发者通过代码直接指定物体在三维空间中的精确坐标值
帧同步机制:在Update()或LateUpdate()生命周期函数中更新位置,确保每帧渲染前完成坐标计算
适用场景
- 非物理相关的瞬移效果(如传送点)
- 精确路径移动(如沿预定轨道运动)
- UI元素的定位控制
- 需要完全掌控运动轨迹的场合
性能考量:相比Rigidbody物理移动,直接修改position避免了物理计算开销,但需注意:
- 频繁修改可能触发OnTransformChanged事件
- 与碰撞体配合时需使用Physics.SyncTransforms
代码示例:
public float speed = 5.0f;
void Update()
{
transform.position += new Vector3(0, 0, speed * Time.deltaTime);
}
这种移动方式如同在方格纸上绘制运动轨迹,每个坐标点都清晰可见,特别适合需要精确控制位移的初学者和特定场景开发。
4.1.2 Transform.Translate
在Unity游戏开发中,Transform.Translate方法是一种高效实现游戏对象平滑移动的常用工具。它通过每帧调用(如在Update或FixedUpdate函数中),每秒向指定方向移动固定距离。
例如:使用transform.Translate(Vector3.forward * speed * Time.deltaTime)可以让对象每秒沿其前方移动speed个单位距离。
这种方式与直接设置Transform.position属性(如transform.position += Vector3.forward * speed * Time.deltaTime)在移动效果上基本一致,两者都能实现对象的位移。
然而,两者在坐标处理上存在关键差异:当移动需要基于对象的局部坐标系时(例如,对象旋转后需沿自身朝向移动),Transform.Translate方法会自动处理从本地坐标到世界坐标的转换。这避免了手动转换的繁琐步骤,如使用Transform.position时需额外调用transform.TransformDirection来调整方向。因此,在涉及坐标转换的场景下,Transform.Translate不仅简化了代码,还提升了开发效率和可读性。
语法:
transform.Translate(Vector3向量,坐标系(默认为Space.Self));
4.1.2.1 Input输入移动
transform.Translate()是非物理移动使用的比较频繁的一种方式,无论是2D还是3D,适用范围都比较广,我们根据官方给出的函数结合Input类函数实现前后左右移动。
代码示例:
void Update()
{
if (Input.GetKey(KeyCode.W))
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.S))
{
transform.Translate(Vector3.back * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.A))
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D))
{
transform.Translate(Vector3.right * speed * Time.deltaTime);
}
}
动作移动略显生涩,关键帧代码存在重复,且输入响应受帧率制约。
4.1.2.2 GetAxis输入移动
同样使用transform.Translate()方法,只是将Input.GetKey()替换为GetAxis()。
当把轴映射到键盘操作时,其数值范围会超出-1到1的区间。此时的实际值等于当前键盘增量乘以轴灵敏度参数。按照惯例,正值对应键盘向右或向前移动,负值则对应向左或向后移动。需要注意的是,这个数值是独立于帧率计算的,因此使用时无需考虑帧率波动的影响。
代码示例:
void Move2()
{
float h = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
float v = Input.GetAxis("Vertical") * speed * Time.deltaTime;
Vector3 thisVec = new Vector3(h, 0, v);
transform.Translate(thisVec);
}
4.2 Rigidbody
Rigidbody 组件利用物理引擎来精确控制物体的位置。使用此组件移动物体时,建议在 FixedUpdate 方法中更新数据,因为该方法会在每次物理模拟前自动调用,比 Update 方法更能确保物理运算的准确性。
4.2.1 Rigidbody.AddForce
为刚体施加一个方向力,使其开始运动。此方法适合模拟外力作用下的刚体行为,如子弹发射。
注意事项:该力是累积作用的,不适合通过重复施加力来维持物体运动。
语法:AddForce(Vector3 force, ForceMode mode = ForceMode.Force);
ForceMode 参数说明:
- Force(默认):持续施加的力,受质量影响
- Acceleration:持续施加的加速度,不受质量影响
- Impulse:瞬间冲击力,受质量影响
- VelocityChange:瞬间速度变化,不受质量影响
代码示例:使用WASD控制移动
private float speed = 10f;
public Rigidbody rig; //获取当前物体的刚体组件
//WASD控制移动示例:
void Update()
{
float h = Input.GetAxis("Horizontal") * speed; //充当force力
float v = Input.GetAxis("Vertical") * speed;
rig.AddForce(new Vector3(h, 0, v));
}
缺点:若要达到理想效果,还需额外配置速度控制与力度控制参数,且这些设置需与重量及角速度参数相互配合。
优点:能提供更真实的手感和视觉效果,若参数调节得当,可带来出色的使用体验。
4.2.2 Rigidbody.MovePosition
移动刚体到一个新的位置,移动的同时受到物理模拟的影响。
语法:Rigidbody.MovePosition(新的位置(Vector3));
代码示例1:
public Vector3 newPosition = new Vector3(0, 0, 1);
public Rigidbody rig; //获取当前物体的刚体组件
void FixedUpdate()
{
rig.MovePosition(transform.position + newPosition * Time.deltaTime);
}
代码示例2:使用WASD控制移动
public Rigidbody rig; //获取当前物体的刚体组件
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
rig.MovePosition(transform.position + new Vector3(h, 0, v) * speed * Time.deltaTime);
}
4.2.3 Rigidbody.Velocity
Rigidbody.Velocity 可以立即赋予物体恒定速度并保持运动状态,特别适合实现跳跃功能。与 AddForce 相比,它能确保每次跳跃高度一致。使用时需要注意在每次跳跃后将速度归零。
代码示例:
public Vector3 high = new Vector3(0, 10, 0);
public Rigidbody rig; //获取当前物体的刚体组件
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
rig.velocity = high;
}
}
4.3 Character Controller
4.3.1 CharacterController.SimpleMove
以一定速度移动角色,以秒为单位,无需乘以时间,具备重力。
语法:CharacterController.SimpleMove(有方向的力(Vector3));
代码示例:
public float speed = 6;
public CharacterController myCC; //获取当前物体的刚体组件
void Update()
{
myCC.SimpleMove(transform.forward * speed);
}
4.3.2 CharacterController.Move
以一定速度移动角色,不具备重力,需要自行计算下落。
语法:CharacterController.Move(有方向的力(Vector3));
代码示例:
public float speed = 5;
public CharacterController myCC; //获取当前物体的刚体组件
void Update()
{
myCC.Move(transform.forward * speed * Time.deltaTime);
}
这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!
更多推荐



所有评论(0)