1. 刚体物理
1.1 刚体
在Unity中,刚体(RigidBody) 组件提供了一种基于物理的方式来控制游戏对象的移动和位置。使用模拟的物理力和扭矩来移动游戏对象,并让物理引擎计算结果,而不是“变换”属性。刚体属性施加来自物理系统的力和扭矩,从而改变游戏对象的变换;如果直接更改“变换”,Unity将无法正确计算物理模拟,并且您可能会看到不需要的行为。对于具有关节的刚体尤其如此。
变换与刚体的最大区别在于力的运用。刚体可以接受力和扭矩,但变换不能。变换可以被平移和旋转,但这与使用物理引擎不同。亲自尝试使用二者会注意到明显的差异。向刚体施加力/扭矩实际上会改变对象的变换组件位置和旋转。这就是为何应该只使用其中一个组件的原因。使用物理引擎时更改变换可能会导致碰撞和其他计算问题。
必须先将刚体显式添加到游戏对象中,然后才能让刚体受到物理引擎的影响。可以从菜单中的 Components > Physics > Rigidbody 向所选对象添加刚体。现在对象已经完成物理设置;它会受到重力的影响而掉落,而且可以通过脚本来接受作用力,但可能需要添加一个__碰撞体__或关节来让对象按照期望的方式运行。
当带有刚体的游戏对象通过基于物理的移动进行移动时,它的移动独立于任何父游戏对象或子游戏对象。具有刚体的子游戏对象仍然使用其父游戏对象来定义。
1.2 碰撞器
碰撞器(Collider)定义刚体的物理边界。若要允许发生碰撞,必须将碰撞器添加到刚体旁边的游戏对象中。如果一个刚体与另一个刚体碰撞,则物理引擎仅在两个游戏对象都连接了碰撞器的情况下计算碰撞。如果一个游戏对象有刚体但没有碰撞器,它会穿过其他游戏对象,Unity不会将其包含在碰撞计算中。
碰撞体是简单形状,如方块、球形或者胶囊形,在 Unity 3D 中每当一个 GameObjects 被创建时,它会自动分配一个合适的碰撞器。一个立方体会得到一个 Box Collider(立方体碰撞体),一个球体会得到一个 Sphere Collider(球体碰撞体),一个胶囊体会得到一个 Capsule Collider(胶囊体碰撞体)等。
- Box Collider

1.3 触发器
触发器是在选中“是触发器”复选框的情况下启用的(见上图Box Collider中第二行)。这与对撞机的功能相同,但会禁用组件上的“物理”,使对象能够通过区域穿过它。当对象进入或退出触发器时,可以调用事件。
在unity3D中要实现触发检测,需要满足以下条件:
1、两个物体都具有Collider组件
2、至少有一个物体拥有Rigidbody组件
3、至少有一个物体的Collider组件勾选了Is Trigger
1.4 恒定力 Constant Force
恒定力 (Constant Force) 可用于快速向刚体添加恒定力。如果不希望某些一次性对象以较大的速度开始而是逐渐加速(比如火箭),则很适合使用恒定力,要制作一个向前加速的火箭,请将 Relative Force 设定为沿正 z 轴。然后,使用刚体的 Drag 属性使其不超过某个最大速度(阻力越高,最大速度越低)。在刚体中,还要确保关闭重力,以便火箭始终保持在其路径上。
属性: | 功能: |
---|---|
Force | 要在世界空间中应用的力的矢量。 |
Relative Force | 要在对象的局部空间中应用的力的矢量。 |
Torque | 在世界空间中应用的扭矩的矢量。对象将开始_围绕_此矢量旋转。矢量越长,旋转越快。 |
Relative Torque | 在局部空间中应用的扭矩的矢量。对象将开始_围绕_此矢量旋转。矢量越长,旋转越快。 |
- 要使对象向上运动,请添加具有正 Y 值 Force 属性的恒定力。
- 要使对象向前飞行,请添加具有正 Z 值 Relative Force 属性的恒定力。
2. 关节
关节将一个刚体连接到另一个刚体或空间中的固定点。关节应用移动刚体的力,而关节限制会限制这种移动。关节赋予刚体以下自由度:
属性: | 功能: |
---|---|
Character Joint | 模拟球窝关节,例如臀部或肩膀。沿所有线性自由度约束刚体移动,并实现所有角度自由度。连接到角色关节 (Character Joint) 的刚体围绕每个轴进行定向并从共享原点开始转动。 |
Configurable Joint | 模拟任何骨骼关节,例如布娃娃中的关节。您可以配置此关节以任何自由度驱动和限制刚体的移动。 |
Fixed Joint | 限制刚体的移动以跟随所连接到的刚体的移动。当您需要一些可以轻松相互分离的刚体,或者您想连接两个刚体的移动而无需在 Transform 层级视图中进行父级化时,这种关节很有用。 |
Hinge Joint | 在一个共享原点将一个刚体连接到另一个刚体或空间中的一个点,并允许刚体从该原点绕特定轴旋转。用于模拟门和手指关节。 |
Spring Joint | 使刚体彼此分开,但使刚体之间的距离略微拉伸。弹簧就像一块弹性物,试图将两个锚点一起拉到完全相同的位置。 |
2D 关节在名称中有 2D 字样,例如,Hinge Joint 2D(2D 铰链关节)。
关节还有其他可用于实现特定效果的选项。例如,可设置一个关节,确保在刚体施加到关节的力超过某个阈值时破坏关节。一些关节允许在连接的刚体之间产生__驱动力__以使它们自动运动。
关节种类包括:
- Hinge Joint 铰链关节
1、铰链关节 (Hinge Joint) 将两个刚体组合在一起,对刚体进行约束,让它们就像通过铰链连接一样移动。
2、铰链关节非常适合用于门,但也可用于模拟链条、钟摆等对象
- Fixed Joint 固定关节
1、 固定关节 (Fixed Joint) 将对象的移动限制为依赖于另一个对象。这有点类似于管控 (Parenting),但是实现的方式是通过物理系统而不是变换 (Transform) 层级视图。
2、使用固定关节的最佳场合是在希望对象可以轻松相互分离时,或者在没有管控情况下连接两个对象的移动。
- Spring Joint 弹簧关节
1、弹簧关节 (Spring Joint) 将两个刚体连接在一起,但允许两者之间的距离改变,就好像它们通过弹簧连接一样
Character Joint 角色关节
1、角色关节 (Character Joint) 主要用于布娃娃效果。此类关节是延长的球窝关节,可在每个轴上限制该关节
- Configurable Joint 可配置关节
1、可配置关节 (Configurable Joint) 包含其他关节类型的所有功能,并提供更强大的角色移动控制。
2、当您想要自定义布娃娃的运动并对角色强制实施某些姿势时,这种关节特别有用。
3、使用可配置关节还可以将关节修改为您自行设计的高度专业化关节
3. 角色控制器 Charactor Controller
第一人称或第三人称游戏中的角色通常需要一些基于碰撞的物理特性,这样它就不会从地板上掉下来或穿过墙壁。在许多应用程序中,角色的加速和移动在物理上是故意不真实的,因此角色几乎可以立即加速、制动和改变方向,而不受动量的影响。解决方案是使用专门的角色控制器。
角色控制器只是一个胶囊形状的__碰撞体__,可以通过脚本来命令这个碰撞体向某个方向移动。然后,控制器将执行运动,但会受到碰撞的约束。控制器将沿着墙壁滑动,走上楼梯(如果低于 Step Offset 值),并走上 Slope Limit 设置范围内的斜坡。角色控制器无法穿过场景中的静态碰撞体,因此将紧贴地板并被墙壁阻挡。控制器可以在移动时将刚体对象推到一边,但不会被接近的碰撞加速。这意味着可以使用标准 3D 碰撞体来创建供控制器行走的场景,但您不受角色本身的真实物理行为的限制。
属性: | 功能: |
---|---|
Slope Limit | 将碰撞体限制为爬坡的斜率不超过指示值(以度为单位)。 |
Step Offset | 仅当角色比指示值更接近地面时,角色才会升高一个台阶。该值不应该大于角色控制器的高度,否则会产生错误。 |
Skin width | 两个碰撞体可以穿透彼此且穿透深度最多为皮肤宽度 (Skin Width)。较大的皮肤宽度可减少抖动。较小的皮肤宽度可能导致角色卡住。合理设置是将此值设为半径的 10%。 |
Min Move Distance | 如果角色试图移动到指示值以下,根本移动不了。此设置可以用来减少抖动。在大多数情况下,此值应保留为 0。 |
Center | 此设置将使胶囊碰撞体在世界空间中偏移,并且不会影响角色的枢转方式。 |
Radius | 胶囊碰撞体的半径长度。此值本质上是碰撞体的宽度。 |
Height | 角色的__胶囊碰撞体__高度。更改此设置将在正方向和负方向沿 Y 轴缩放碰撞体。 |
4. 项目练习
4.1 碰撞刚体球
1. 在Unity Hub新建一个 3D Core 项目,在unity editor 打开该项目,
4.1.1 新建环境
2. 在 Hirarchy 窗口,在空白处点击鼠标右键,在弹出菜单中选择 3D Object > Plane,在场景中新建一个平面;
3. 在 Project 窗口,把鼠标放在 Assets 上,然后点击鼠标右键,在弹出菜单上选择 Create > Folder, 更改这个新建的 folder 的名字为 Materials;
4. 在新建的Materials 文件夹上点击右键,在弹出菜单上选择 Create > Materials, 新建一个材质,命名为 Plane,
5. 选择该 Plane 材质,在右侧 Inspector 窗口的 Albedo 处,点击右边白色框,在弹出的颜色窗口选择一个较为暗色的颜色,然后将该材质Plane 应用用于场景中刚刚新建的平面Plane 游戏物体;
6. 在 Hirarchy 窗口的空白处再次点击鼠标右键,选择3D Object > Cube, 使用 Scene 窗口左侧的工具按键,将该 cube de 形状拉升如下图所示大小(长度和plan长度差不多),并把Cube 移到plane的一侧,作为一道墙壁;
7. 在 Scene 场景中点击修改后的 Cube, 然后在键盘上按组合键 Ctrl+D,复制该cube,并将这个新的cube移到plane的另外一侧,形成另一堵墙;
8. 重复上述操作,制作另外两堵墙,放在plane的另外两侧,如下图所示:
4.1.2 构建 Player 球游戏物体
9. 在 Hirarchy 窗口空白处,点击鼠标右键,在弹出菜单中选择 3D Object > Sphere,构建一个球体,并将该球体放在plane上面
10. 在右侧Inspector窗口的最下方,点击 Add Component,在弹出窗口中输入 Rigidbody, 鼠标左键点击该名称,给上述球体添加了 Rigidbody属性;
11. 仿照上述步骤3, 在Project 窗口,把鼠标放在 Assets 上,然后点击鼠标右键,在弹出菜单上选择 Create > Folder, 更改这个新建的 folder 的名字为 Scripts;
12. 鼠标右键点击该Scripts 文件夹,在弹出菜单中选择 Create > C# Script, 并将该脚本的名称改为 Player;
13. 双击该Player脚本,打开visual studio 程序,拷贝下面代码,覆盖原先的代码,然后点击保存。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
//刚体
Rigidbody rbody;
// Start is called before the first frame update
void Start()
{
//获取刚体
rbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
//数值范围
// 1
//-1 1
// -1
//获取水平轴
float h = Input.GetAxis("Horizontal");
//获取垂直轴
float v = Input.GetAxis("Vertical");
//获取移动的方向向量
var movement = new Vector3(h, 0, v).normalized;
//在移动方向上发力
rbody.AddForce(movement);
//也可以尝试如下方法改变移动方向
//rbody.velocity = movement;
}
}
14. 点击Hirarchy 窗口中的Sphere 球体物件,然后将上述新建的 Player 脚本拖拽到右侧 Inspector 窗口的最下方,将该脚本添加到该球体;
15. 点击界面 Play 按键(上述图像正上方的三角形按键),然后鼠标点击游戏Game窗口,在按键盘上的前后左右方向按键,可以控制球在平面上的运动 (如果游戏窗口的视角不适合操作,可以改变 Main Camera 的位置,获得一个合适的视角)
4.1.3 构建 Cube 碰撞体
16. 在 Hirarchy 窗口的空白处,点击鼠标右键,在弹出菜单中选择 3D Object > Cube, 将新建的 cube 放在plane上面 (在Hirarchy窗口中该新建的cube名称为 Cube(4)因为前面建围墙已经新建了4个cubes),
17. 仿照上述步骤12, 鼠标右键点击该Scripts 文件夹,在弹出菜单中选择 Create > C# Script, 并将该脚本的名称改为 Pickup;
18.双击该Pickup脚本,打开visual studio 程序,拷贝下面代码,覆盖原先的代码,然后点击保存。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pickup : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//每图像帧旋转
transform.Rotate(new Vector3(30, 30, 30) * Time.deltaTime);
}
}
19. 点击Hirarchy 窗口中的 Cube(4) 游戏物件,然后将上述新建的 Pickup脚本拖拽到右侧 Inspector 窗口的最下方,将该脚本添加到该Cube 游戏物件;
20. 再次点击界面 Play 按键(上述图像正上方的三角形按键),然后鼠标点击游戏Game窗口,可以看到方块Cube(4)能够自己旋转,再按键盘上的前后左右方向按键,控制球在平面上的运动,球碰到 Cube(4) 的时候,两个游戏物体有碰撞效果,但该 cube 没有消失
4.1.4 制作吃方块效果
21.然后在双击 Player 脚本文件,在visul studio中再次打开该脚本文件,在原有的代码中加入如下黑体的代码,然后点击保存 (记住修改代码后一定要在visual stuido 中保存)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
//刚体
Rigidbody rbody;
// Start is called before the first frame update
void Start()
{
//获取刚体
rbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
//数值范围
// 1
//-1 1
// -1
//获取水平轴
float h = Input.GetAxis("Horizontal");
//获取垂直轴
float v = Input.GetAxis("Vertical");
//获取移动的方向向量
var movement = new Vector3(h, 0, v).normalized;
//在移动方向上发力
rbody.AddForce(movement);
//也可以尝试如下方法改变移动方向
//rbody.velocity = movement;
}
private void OnTriggerEnter(Collider other)
{
if (other.GetComponent<Pickup>())
{
other.gameObject.SetActive(false);
}
}
}
22. 返回 Unity Editor界面,在 Hirarchy 窗口点击 Cube(4) 游戏物体,在右侧 Inspector 窗口中的 Box Collider 属性中勾选 Is Trigger, (见上图中的勾选位置)
23. 再次点击界面 Play 按键(上述图像正上方的三角形按键),然后鼠标点击游戏Game窗口,可以看到方块Cube(4)能够自己旋转,再按键盘上的前后左右方向按键,控制球在平面上的运动,球碰到 Cube(4) 的时候,该 cube 消失了!
24. 在 Project 窗口中,鼠标右键点击Assets,在弹出菜单中选择 Create > Folder, 新建一个文件夹,命名为 Prefabs (见下图);
25. 在 Hirarchy 窗口中,鼠标左键选择 Cube(4), 拖拽该游戏物体到新建的 Prefabs 文件夹,这样就构建了一个预制体(见下图);
26. 然后在该 Prefabs 文件夹中用鼠标左键拖拽 Cube(4)预制体到 Hirarchy 窗口中,重复拖拽 5 次,这样在场景中生成了具有同样属性的 5 个cube方块,将这5个方块移到场景中的不同位置,如下图所示:
27. 再次点击界面 Play 按键(上述图像正上方的三角形按键),然后鼠标点击游戏Game窗口,可以看到所有的方块能够自己旋转,再按键盘上的前后左右方向按键,控制球在平面上的运动,球碰到 每个方块cube的时候,该 cube 消失了!
28. 退出游戏,再点击左上方菜单 File > Save, 保存该场景,然后退出该项目。
4.2 Unity playground
unity 碰撞教程 Unity Playground
资源下载: Asset Store:Unity Playground
1. 在Unity Hub新建一个 Univeral 3D 项目,在unity editor 打开该项目,
2. 点击上述Asset Store链接,登录网页后点击“Open in Unity”, 在弹出窗口中选择“打开Unity Editor”。
4.2.1 下载级导入资源包
3. Unity 界面中 Package Manager窗口弹出,点击 “Download”按键,下载完毕后,点击 Import
4. 弹出如下窗口,继续点击 “Import”, 如果弹出窗口提示要覆盖原有项目,点击 继续。
-
4.2.2 新建玩家player
5. 导入完成后,在Project窗口, Assets > UnityTechnologies > Playground > Images > Spaceships 目录下选择一个飞船图像,拖拽到左侧的 Hierarcy 窗口,呈现在场景中的图像如下图所示,更改名称为 Ship, 设置Tag 为 Player。
注意:
如果下面的Game窗口中没有显示天空盒或者移动spaceship有残影,这可能与显示设置有关,更改显示设置, 点击菜单 Edit > Project Setting, 显示如下窗口
点击左侧Graphics项,然后在右侧的第一行 Scriptable Render Pipline Setting中更改当前的Render Pipline 为 None,回到主界面就可以看到Game 窗口显示天空盒了
另外,由于当前是2D游戏,可以将Scene窗口显示为2D,方便查看
6. 在Project窗口打开 Assets > UnityTechnologies > Playground >Scripts >Movement, 将该目录下的 move 脚本拖到右边的 Inspector窗口,给 Ship 游戏对象增加一个脚本属性,如图:
7. 在上述图像右边的 Inspector 窗口中,将Gravity Scale 值从 1 改为 0, 将脚本中 Speed 从 5 改为 1;
8. 点击界面中间正上方的 运行按键,点击Game(游戏)窗口,在按 “上、下、左、右” 方向键,控制场景中飞船的运动。
(可以尝试将Gravity Scale 值保持为 1,运行游戏,可以看到飞船掉落下去 :)
-
4.2.3 新建障碍物陨石
9. 在Project窗口,Assets > UnityTechnologies > Playground > Images > Asteroids 目录下选择1个物体(例如 Asteroid2)放到Hierarchy窗口,点击该新加入的游戏对象,在右侧 Inspector 窗口中点击最下端 “Add Component”,选取 Rigidbody 2D,添加该属性到此游戏对象,如图所示:
10. 在Rigidbody 2D属性中设置 Gravity 为 0, Mass 值为 10, ;
(这时可以尝试运行游戏,操纵飞船去撞击石头,会有什么发现?)
11. 在 Hierarchy 窗口中同时选择 Ship 和 Asteroid2 两个游戏对象,再点击右侧 Inspector 窗口中点击 “Add Component” 按键,选取 PolygonCollider2D,添加该属性到这两个选择的游戏对象。
12. 再次点击界面中间正上方的 运行按键,点击Game(游戏)窗口,在按 “上、下、左、右” 方向键,控制场景中 Ship (飞船)的运动,使之与 Asteroid2 相撞!
-
4.2.4 添加玩家生命点数
13. 在Project窗口,Assets > UnityTechnologies > Playground > Scripts > Attributes 目录下选择 ModifyHealthAttribute 脚本文件,同时在 Hierarchy 窗口选择 Asteroid2 游戏对象,将ModifyHealthAttribute 脚本文件拖到右侧Inspector窗口下方,增加一个脚本属性。
14. 同理,在在 Hierarchy 窗口选择 Ship 游戏对象,再将 Assets > UnityTechnologies > Playground > Scripts > Attributes 目录下 HealthSystemAttribute 脚本文件拖到右侧Inspector窗口下方,增加一个脚本属性。
15. 在 Hierarchy 窗口选择 Asteroid2, 拖到Project 窗口中 Assets > UnityTechnologies > Playground > Prefabs, 如下图:
16. 将Assets > UnityTechnologies > Playground > Prefabs 目录下新加入的 Asteroid2 加入到场景中,在HIerarchy窗口中 显示在已有的 Asteroid2 游戏对象后列。
17. 点击界面中间正上方的 运行按键,点击Game(游戏)窗口,在按 “上、下、左、右” 方向键,控制场景中 Ship (飞船)的运动,使之与 Asteroid2 相撞!
-
4.2.5 建立UI界面
18. 在Project窗口,Assets > UnityTechnologies > Playground > Prefab 目录下选择 UserInterface 脚本文件,加入到场景中,如图所示:
19. 点击界面中间正上方的 运行按键,点击Game(游戏)窗口,在按 “上、下、左、右” 方向键,控制场景中 Ship (飞船)的运动,使之与 Asteroid2 相撞,可以看到界面上 health的值逐渐从3 减到 0。
-
4.2.6 设置游戏目标及胜利的条件
游戏的目标是收集星星,胜利的条件是收集到 5 颗星星,同时避免与陨石碰撞!
20. 在Project窗口,Assets > UnityTechnologies > Playground > Images > GameElements 目录,选择星星加入到场景中,
21. 打开Assets > UnityTechnologies > Playground > Scripts > Attributes,将 Collectable 脚本文件添加到星星属性,如有弹出窗口,选择 Polygon,如下图所示:
22. 在Hierarchy窗口中,将Star拖到右侧 Assets > UnityTechnologies > Playground > Prefabs, 从而将 start 生成一个 Prefab 预制体,再将该预制体加入到场景中,重复 4 次,场景中共有 5 个星星了
23. 在Hierarchy窗口中,选择 UserInterface 游戏对象,在右边 Inspector 窗口中 UI Script脚本中设置 Score to Win 的值为 5.
19. 点击界面中间正上方的 运行按键,点击Game(游戏)窗口,在按 “上、下、左、右” 方向键,控制场景中 Ship (飞船)的运动,收集 5 颗星星,完成目标后,"Player 1 wins!" 的信息将显示在游戏界面上。
参考视频:旧版本 【unity2021入门】13-官方入门教程系列-02-PlayGround-01-宇宙飞船-01-飞起来吧!_哔哩哔哩_bilibili