无论是碰撞检测还是触发检测,他们都基于Collider组件。两个游戏对象发生碰撞时,碰撞器可以产生系统默认的碰撞产生的物理效果;触发器可以让用户自定义碰撞后产生的物理效果,如爆炸、消失等。
在Unity中,用来检测碰撞的方法有三种:碰撞检测、触发检测、射线检测。在这里我们只讲解碰撞检测和触发检测。
一、碰撞检测
首先在Unity里面,碰撞器是一种组件,有很多种类,大致分为两类:基本碰撞器和非基本碰撞器;其中基本碰撞器包括Box Collider(Cube游戏物体自带的碰撞器)、Sphere Collider(Sphere自带的碰撞器)、Capsule Collider(Capsule自带)等,而非基本碰撞器包括Wheel Collider(车轮碰撞器)、Mesh Collider(网格碰撞器,Plane自带)等。
基本碰撞器的属性基本都一样,只是因为形状不一样而有数值上的差异,而非基本碰撞器比较特殊,每一个都可以拿出来单独介绍。这里我们详细讲解一下基本碰撞器,而非基本碰撞器我们后续章节再做详细介绍。
如图1.1和1.2分别是Cube和Sphere自带的碰撞器:
对比两张图片我们可以看出它们都拥有Edit Collider、Is Trigger、Material、Center属性,因为形状的不同才会有了Size和Radius的差别。
1、Edit Collider
单击选中一个游戏对象的Edit Collider选项后,游戏对象身上会出现包裹全身的网格,上面还有光点,如图1.3:
点击鼠标左键拖动光点,就可以改变Size或者Radius等的大小,也就是改变了碰撞器的大小。
2、Is Trigger
这个属性就是碰撞器和触发器的区别,勾选这个属性就是触发器,不勾选就是碰撞器。这里我们先不勾选。
3、Material-材质
默认是None,可以添加其它物理材质(Physic Material),用来设置弹性系数和摩擦系数,上一章有介绍。
4、Center
用来调整Collider的位置,如图1.4:
由图可以看出Collider的位置和游戏对象位置并不冲突,两方都是独立的,一个游戏对象的默认碰撞器的位置和游戏对象本身的位置一致。
5、Unity中碰撞器有三个自带的方法,当游戏对象发生碰撞时调用,他们分别是OnCollisionEnter、OnCollisionStay、OnCollisionExit,这就是所谓的碰撞检测方法。
OnCollisionEnter:两个碰撞游戏对象的碰撞器刚接触时(注意,不是游戏对象接触,是游戏对象上的碰撞器-Collider组件接触)调用一次。
OnCollisionStay:两个游戏对象的碰撞器接触时调用,只要两个碰撞器一直在接触,就会一直调用该方法。
OnCollisionExit:两个游戏对象的碰撞器相互分离时调用一次。
下面用几个情形来说明一下什么条件(两个游戏对象是否带有刚体和碰撞器)下会调用上述三种碰撞检测方法。
情形一:两个游戏对象都具有刚体和碰撞器时
我们先给两个游戏对象(Cube和Sphere)分别添加刚体,这两个游戏对象都自带有碰撞器-Collider,这里我们不要改变Collider的Center的值,让Collider和物体位置一致;然后我们给两个物体都添加一个脚本,脚本的内容就是利用上述三种方法在控制台打印出相应的调用方法的名字。
小球的脚本代码:
<code>
private Rigidbody rb;
// Use this for initialization
void Start () {
rb=GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
// this.transform.Translate(new Vector3(1,0,0));//小球没有刚体时让其移动的方法
rb.AddForce(new Vector3(1, 0, 0));//小球拥有刚体时让其移动的方法
//两种方法根据情形不同选择其中一个
}
}
void OnCollisionEnter()
{
print("小球调用了OnCollisionEnter方法");
}
void OnCollisionStay()
{
print("小球调用了OnCollisionStay方法");
}
void OnCollisionExit()
{
print("小球调用了OnCollisionExit方法");
}
</code>
方块的脚本代码:
<code>
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnCollisionEnter()
{
print("方块调用了OnCollisionEnter方法");
}
void OnCollisionStay()
{
print("方块调用了OnCollisionStay方法");
}
void OnCollisionExit()
{
print("方块调用了OnCollisionExit方法");
}
</code>
把写好的脚本分别加入相应的游戏对象中,然后我们就单击运行按钮,查看Console视图的打印内容,如图情形一:
图情形一.1可以看出小球和方块都调用了OnCollisionEnter和OnCollisionStay方法,其中OnCollisionEnter都只调用了一次(Plane自带的有Mesh Collider),OnCollisionStay方法一直在调用;至于方法调用的先后顺序是:OnCollisionEnter>OnCollisionStay>OnCollisionExit,而之所以先调用了方块的方法是因为方块先落的地。
有上面两个图我们可以得出:当两个游戏对象都拥有刚体和碰撞器时,他们在碰撞时都会打印碰撞器的三种方法。
情形二:小球有刚体和碰撞器,方块只有碰撞器时
如图情形二:
得出:当两个游戏对象一方拥有刚体和碰撞器,另一方只拥有碰撞器时,只要两方发生碰撞,就会调用碰撞方法。
情形三:小球和方块都只有碰撞器,没有刚体
此时小球没有了刚体,我们让它移动要利用另外一种方法,上面代码有写,这里直接用就行了。
如图情形三:
得出:当两个游戏对象只拥有碰撞器,它们互相碰撞接触时不会调用碰撞方法。
情形四:一方(小球)带有刚体和碰撞器,另一方(方块)只带有刚体,没有碰撞器。
如图情形四:
首先我们要把方块的碰撞器组件-Box Collider取消勾选,如图情形四.1:
为了验证小球和方块的碰撞,我们把小球放到了方块的正下方,这样方块落下时就会和小球碰撞接触了,如图情形四.3。
得出:当一方有刚体和碰撞器,另一方只有刚体,两方相互碰撞接触时,都不会调用碰撞方法。
由此得出结论:
两个物体碰撞调用碰撞方法的前提是必须两个物体都拥有碰撞器—Collider,而且其中一方必须带有刚体组件。
二、触发检测
触发检测就要用到触发器,而触发器可以说就是一种特殊的碰撞器,因为只要把碰撞器组件中的Is Trigger属性勾选上,就变成了触发器。
和碰撞检测类似,触发检测也有三种方法,分别是OnTriggerEnter、OnTriggerStay、OnTriggerExit。
触发检测的验证也有很多情形,根据两个游戏对象的条件(是否带有刚体和触发器)的不同大致分为:双方都带有刚体和触发器、一方带有刚体和触发器,另一方只有刚体、一方带有刚体和触发器,另一方只有触发器、双方都只有刚体、双方都只有触发器。
这里就介绍一个情形下(一方带有刚体和触发器,另一方只有刚体)的触发检测方法的调用情况,其它情形自行操作。
当选中Is Trigger后,碰撞器就变成了触发器,如果此时我们再给游戏对象添加一个刚体,那么游戏对象就会一直坠落,因为没有了碰撞器,所以我们要想让游戏对象有刚体而又不坠落,我们就要选中刚体组件中的Is Kinematic属性,如图1.5:
选中后,我们让小球带有刚体和触发器,让方块只带有刚体。此时改一下小球和方块的代码,把触发检测的三个方法写进去,然后我们运行项目,操作小球移动,观察打印结果,如图1.6:
后面几种情形自行实验过后我们就得出了一个结论:
只要有一方游戏对象带有刚体和触发器,另一方不管是否带有刚体和触发器,两个游戏对象都会调用触发检测方法。
三、碰撞检测和触发检测的异同
相同点:
1、两种检测的基础都是Collider组件;
2、两种检测的三种方法类似;
不同点:
1、碰撞检测必须两个Collider组件都不勾选Is Trigger,只要勾选了,就会进入触发检测;
2、触发检测和碰撞检测有冲突,不能同时存在,只能存在一个;