包含了碰撞刚体触发等

本课程学习之前,你可以使用之前的项目或者新建一个项目,添加两个cube或者其他自带的3d模型。并且写一个简单的移动脚本(能让它移动到和另一个3d模型重合的程度),挂在其中一个3d模型上。

(刚体、碰撞体、tag and layer和碰撞)

1、Rigidbody(刚体)

刚体
在开始了解刚体的属性之前我们首先要知道什么是刚体:

官方定义:使游戏对象的行为方式受物理控制。刚体可以接受力扭矩,使对象以逼真的方式移动

实际上就是:可以让对象可以受到“力”,有了“力”就有了碰撞,有了各种各样力学上的动作,有了空气阻力等等性质。

换句话说,如果我们想让一个物体从“不能和任何物体碰撞的虚影”变成一个“可以被物理影响”的实际物体,那么给他上一个刚体就对了。

1.1 给物体上刚体的一般方式

1.1.1 add component

add component
给各种GameObject添加各种组件最简单的方式就是在其属性最下方找到add component,然后输入你想添加的组件名,比如Rigidbody,就可以轻松添加了。

你在这里可能会看到一个Rigidbody 2D,那个是2D部分的东西,我们在之后会细讲2D游戏相关,现在让我们先不要管它。

1.1.2 代码,弱。菜单栏,强

同样的,你可以在component>>Physice下找到rigidbody刚体,点击它会给你当前选中的对象直接套上。

1.2 刚体的属性

1.2.1 Mass(质量)

刚体最基本的属性,默认单位为千克。那么这玩意有什么用呢?建议回忆一下动量定理。

简单来说就是,两个物体碰撞过程中,质量越大的物体受到的影响越小,也就是向外飞的速度越小

mass:左1右1(左边和右边都飞了)
z1u1
mass:左10000右1(左边几乎不动,右边飞了)
z10000u1

1.2.2 Drag(空气阻力)

懂的都懂,0表示没有空气阻力,物体会沿惯性一直走。
但是值得一提的是,这个空气阻力针对的是“移动”,不管旋转的事情。

1.2.3 Angular Drag(旋转空气阻力)

如名,这个空气阻力针对的是旋转,0表示没有空气阻力。

1.2.4 Use Gravity(重力)

该选项决定了物体是否受到重力影响。
当我们选择这个选项的时候,物体会持续受到竖直向下的重力影响。(所以如果你做的游戏不需要重力,就把它关掉吧)

1.2.5 Is Kinematic(运动学)

该选项决定了物体是否会受到“物理”影响。
简单来说,就是当我们勾选了它之后,物体就不会再像刚才一样受到碰撞的影响了。
我们依然可以用代码控制它的transform属性,来实现对它的旋转控制等,也可以操控它去撞那些并非勾选Is Kinematic的对象,你就像是坦克车一样,撞谁谁飞而你自己却完全不会动。

1.2.6 Interpolate(插值)

插值,一般用来消除以固定帧率运行导致的卡顿。如果你是以第三人称视角制作游戏,可以为主角添加插值以防止物理和图形并不完全同步导致的卡顿现象。

选项 介绍
None 不使用插值
Interpolate 根据前一帧的Transform来进行平滑变换
Extrapolate 根据估算的接下来一帧的Transform来进行平滑变幻

1.2.7 Collision Detection(碰撞检测)

在提到这个之前,你首先要理解unity的移动是怎么完成的。

比如现在你有一个小球,位置在0,它的速度的1/帧。
那么第一帧,它的位置就由0变成了1,第二帧就由1变成了2,以此类推。

但是这样的碰撞检测会遇到一个问题——如果它速度过快,就会跳过一部分空间。比如它的速度是10/帧,那么它前进的过程中,就会直接跨过1-9的部分,到达10。这样一来,它就无法和1-9空间内的物体发生碰撞了。

本选项用于直接解决问题,实际上我们在使用过程中更多会采用射线来解决这个问题,这一点我们会在提到射线的时候细讲。

选项 介绍
Discrete 离散检测,一般情况下的默认选项,性能相对较高。
Continuous 连续检测。简单来说就是对动态碰撞体采用离散(也就是默认),对静态碰撞体(也就是没有刚体,但是又碰撞体的物体)采用连续检测来避免我们提到的跳跃过物体的情况。但是这一项会极大地增加资源损耗。
Continuous Dynamic 动态连续检测。如果其他物体是Continuous(连续检测)、Continuous Dynamic(动态连续检测)或者静态碰撞体(没有刚体的)都采用连续检测。对其他采用离散检测。

1.2.8 Constraints(运动约束)

下设两个小分类:
Freeze Position:刚体不会在对应的轴上移动
Freeze Rotation:刚体不会在对应的轴上旋转

关于这个,只能说,自己试试比什么都有用。

2、Collider(碰撞体)

碰撞体是什么?最直接的解释就是——给我们的游戏对象一个“可碰撞的形状”。

简单来说,想要碰撞,只有“刚体”,只是让它可以接受力,但能接受力,没有碰撞的形状,也一样不能碰撞——两个虚无的存在碰个屁。因此我们如果想要一个物体可以和另一个物体碰撞,就需要给他们“形状”,也就是碰撞体了。

你可以在component > Physice找到各种各样的碰撞体。
collider

2.1 Edit Collider

点击右边那个小按钮之后,你就可以修改这个碰撞体的样子了,具体请自己试验,一用就会的。

2.2 Is Trigger(触发)

当你将is Trigger打钩之后,很快就会发现一个问题:直接撞过去,物体会直接穿过被打钩的对象。

但是如果我们使用碰撞检测代码(等等会讲)来检测的话,会发现碰撞依然被触发了。

因此,你可以理解为,当你打钩后,物体成为了一个虚体:它不会被碰撞直接影响位置等,但依然会响应碰撞。比如子弹打到对方身上,对方不会被子弹打飞,但是会扣血

2.3 Physic Material(物理材质)

用于添加物理材质给碰撞体。

既然这里提到了物理材质,那么我们也就顺便说一下什么是Physic Material(物理材质)。简单来说,就是一种用来处理对象碰撞摩擦和反弹的通用模板。

你可以通过Assets > Create > Physic Material来创建一个物理材质,然后将物理材质拖动到碰撞体上。
Physic Material

2.3.1 Dynamic Friction(动态摩擦力)

Dynamic Friction动态摩擦力决定了物体在移动过程中使用的摩擦力大小,区间为0~1。当其移动摩擦力为0时,和冰块一样。为1时则会迅速停止。我们依然可以使用很大的力推动它。

2.3.2 Static Friction(静态摩擦力)

Static Friction静态摩擦力,决定了物体在静止状态下使用的摩擦力大小,区间一样为0~1.当其摩擦力为0时,和冰块一样,为1时则会让物体很难开始移动。

2.3.3 Bounciness(弹性)

如题,范围0~1。0不会反弹,1反弹不会有能量损失。

2.3.4 Friction Combine(摩擦力组合)、

该选项决定了如果两个对象摩擦后,将如何决定两个对象的综合摩擦力,其下有四个选项:

选项 介绍
Average 综合摩擦力为两个摩擦力的平均值
Minimum 使用两摩擦力的最小值
Maximum 使用两摩擦力的最大值
Multiply 摩擦力相乘

2.3.5 Bounciness Combine(弹性组合)

决定了两个对象碰撞后的弹性,将如何计算其相对的综合弹性,选项和2.3.4摩擦力组合完全相同。

3、Tags and Layer

tags和layer一般用作区分物体的属性等。
我们可以从Edit > Project Settings > Tags and Layers打开它的控制台。

选项

3.1 Tags(标签)

tags就是单纯的标签,每个物品都能有一个标签,我们一般用表现来识别物品的种类。

标签一般是用于在碰撞等操作中进行物体判断的,比如我们可以在代码中写“子弹碰到敌人,敌人扣血。而子弹碰到队友,队友扣双倍血。”这样,我们就需要两个标签:敌人和队友,分别赋予两个目标。

一般情况下,我们可以在该面板修改表现或者增加标签,在gameobject面板下可以编辑物体的tags。
gameobject面板

3.1.1 GameObject.FindWithTag(查找对象)

一般情况下,我们可以通过tag去寻找特定的对象。

比如现在场上的两个cube,我们增加一个tag叫做“mycube”,然后赋予给其中一个,如下:
cube

紧接着,我们在另一个cube的脚本中,使用GameObject.FindWithTag来找到我们有着mycube标签的cube:

public GameObject m_myobj;

    void Start()
    {
        m_myobj=GameObject.FindWithTag("mycube");
    }

通过这样,我们就能在一个物体中读取另一个物体的数据了。我们也可以通过

 m_myobj.transform.Translate(new Vector3(0.1f, 0, 0), Space.World);

等,直接用我们已经读取到的物体的transform属性来控制其移动。

除了FindWithTag外,还有类似:
FindGameObjectWithTag(准确寻找带标签的GameObjects,返回一个GameObject
FindGameObjectsWithTag(准确寻找所有带标签的GameObjects,返回GameObjects数组

3.2 Layers(图层)

除了系统默认图层外,我们也可以设置很多我们自定义的图层。图层的作用是让我们更有效的划分“一类物体”是否被渲染,或者他们的渲染模式等。一般来说,如果我们要将图层分级,让他们呈现不同的效果(比如背景,特效,前景),就会将它们分为不同的layers。

4、碰撞检测

一般意义上,我们将碰撞检测分为两个部分讨论,它们分别是碰撞检测和触发检测。

4.1 OnCollision(碰撞检测)

想要完成碰撞,需要满足以下条件:

  1. 主动碰撞方有刚体(Rigidbody)
  2. 双方都有碰撞体(Collider)

碰撞检测常用三个函数,我们直接将其在类中重写:

public class move : MonoBehaviour
{
	void OnCollisionEnter(Collision collisionInfo)
    {
    	这个部分表示,当两个物体碰撞开始时,调用该函数内语句
    }
    void OnCollisionExit(Collision collisionInfo)
    {
		当两物体碰撞结束后,调用该函数内语句
    }
    void OnCollisionStay(Collision collisionInfo)
    {
		当两物体处个于碰撞期间,调用该函数语句
    }
}

这里的collisionInfo,表示的是被动方。

我们可以通过调用其gameobject组件,来完成对其的控制,比如:

collisionInfo.gameObject.transform ......

这样,我们就可以通过调用被碰撞体(被动方)的tag来区分碰撞到不同物体时,造成的影响了。比如如果它碰到了mycube,就让它自毁。

	if (collisionInfo.gameObject.tag == "mycube")
    {
		Destroy(this.gameObject);
    }
    else if (collisionInfo.gameObject.tag == "othercube")
    {
		...
    }

4.2 OnTrigger(触发检测)

和碰撞检测类似的,还有另一种检测方式:触发检测,它需要满足以下条件:

  1. 双方都有碰撞体(Collider)
  2. 双方之一有刚体(Rigidbody)
  3. 双方之一的碰撞体(Collider)勾选了Is Kinematic(忘记这个是什么的请往前翻)
    它的语句是:
	void OnTriggerEnter(Collider other)
    {

    }
    void OnTriggerExit(Collider other)
    { 
    
    }
    void OnTriggerStay(Collider other)
    {

    }

这里的other表示的是被碰撞方,我们同样可以使用other.gameObject来调用other的一些参数并使用其方法。