Unity --- 物理引擎 --- 触发器 与 碰撞器详解

Posted Metallic Cat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity --- 物理引擎 --- 触发器 与 碰撞器详解相关的知识,希望对你有一定的参考价值。

碰撞器补充讲解

对第一个条件进行补充 --- 不仅要两者都具有碰撞组件,同时还需要两者的碰撞组件中都没有勾选 Is Trigger属性

 1.上一篇文章中说了那么多,其实也可以总结为两个碰撞条件 --- a.两个游戏物体都具有碰撞器组件 ,如果没有的话,连碰撞检测都不会发生,也就没有所谓的碰不碰撞一说了

b.运动的物体具有刚体组件 --- 在有刚体组件的前提下,物体只有处于运动状态时才具有

1.第一个阶段会在两个物体接触的第一帧执行 --- 只执行一次

2.第二个阶段会在两个物体保持接触时每帧执行 --- 每帧执行

3.第三个阶段则是在两个物体分离的那一帧执行 --- 只执行一次

4.collision(名词.碰撞) --- 上面那个Collision是一个类 --- 其实就是碰撞器类

1.碰撞阶段的三个方法都有一个参数 --- Collision other --- 这个参数的类型是碰撞器类 --- 当挂载该脚本的游戏物体a与其它具有碰撞器组件的游戏物体b发生碰撞时, 游戏物体b的碰撞器组件对象就会被传给三个方法中的引用参数 Collision other.

(注意!!! 碰撞器组件对象是被传给了Collision类内部的一个引用 --- 该引用的类型是Collider,引用名就是 collider  --- 如果说想访问碰撞器组件对象的话得通过 对应类型的参数名 + 点操作符 + 类中的引用的引用名)

2.注意!只有满足了两个碰撞条件(a.都具有碰撞器组件 b.运动的物体上具有刚体组件  --- 不处于运动状态的话则刚体组件处于休眠状态)之后才能够开始执行碰撞的三个阶段对应的方法 --- 对了写有方法的脚本也得挂载到游戏物体上并启动才行


触发器讲解

碰撞器组件中勾选了Is Trigger属性的游戏物体无论是撞别人还是被别人撞都不会产生碰撞效果而是直接穿过去

 1.碰撞器组件中的Is trigger属性被勾选后就转变为了 --- 触发器

触发器与碰撞器的区别就是 --- 触发器不会产生碰撞效果

1.注意!只需要带有刚体组件即可,不需要处于运动状态

1.满足触发条件之后就会开始执行触发三阶段所对应的方法 

注意碰撞三阶段与触发三阶段之间的 --- a.方法区别 b.方法的参数的类型区别(一个是Collision类名词碰撞,类中有一个Collider类型的引用  ; 另一个是Collider类 名词碰撞器,它就是碰撞器类型)


Collision类 与 Collider类

1.Collision类中包含一个引用,该引用的类型是Collider,引用名是collider

2.Collider类就是碰撞器类,游戏物体挂载的碰撞器组件对象类型就是Collider

3.Collision类还包含一个很重要的引用 --- contacts

1.contact(v.接触)

2.这个引用的类型是 ContactPoint[ ] --- 也就是说这个引用是一个数组引用,它指向的是一个存放两个物体发生碰撞时的接触点的数组

3..通过这个引用 + 索引,我们能够访问到碰撞点 

4.碰撞点类型 --- ContactPoint中有两个比较重要的属性 --- point  /  normal

两者的类型都是Vector3类,不过point表示的是接触点的坐标,而normal表示的是接触面的法向量

5.一个游戏物体可以拥有多个碰撞器组件以此来实现多重碰撞检测,一般来说都是一个碰撞器用来作为触发器,一个碰撞器用来模拟物理效果的(说白了就是一个有Is Trigger ,一个没有Is Trigger)

1.如果物体移动速度过快的话,碰撞检测将失效,此时需要我们更换检测方式  --- 使用射线检测法来进行替代

2.射线检测方法被封装在了Physics类中 --- 方法名:Raycast() -- 为静态方法 --- 这个方法的一个重载方法的参数中有一个比较特别的参数  ---- 参数的类型是 out RaycastHit --- 这个参数被out 修饰,是一个输出参数,也就是说在方法调用的时候会将一些计算结果赋值给这个参数 --- 这个参数的使用方法是:

a.在调用方法前建立一个无out的参数 -- 如上图,然后将其传参给函数,函数调用过程中将一些结果赋值给这个参数,这个参数再传给外面的无out同类型的传参源头引用

b.RaycastHit类对象是用来记录射线检测到的各种数据的,如射线检测到的点的坐标,射线检测到的面的法向量等等 --- 具体可以查看该类的内部

3.该方法除了在调用过程中传参给输出(out)参数外,在方法调用结束的时候也会返回一个bool值 --- bool值为true则意味着射线检测到了物体,反之就是没有检测到物体

4.通过射线检测来进行碰撞判定,说白了就是在物体运动之前就计算和设计好了是否会碰撞,如果没碰撞发生什么,如果碰撞了又发生什么,以及物体怎么运动 --- 通过这种方式能够规避掉边运动边检测(如逐帧检测)可能带来的失效问题

转载 unity3d 理解刚体(Rigidbody)和碰撞体(Collider)以及触发器(Is Trigger)

和好的文章,有一些原作者的结论很经典。

刚体(Rigidbody)的官方(摘自Unity3d的官方指导书《Unity4.x从入门到精通》)解释如下:

Rigidbody(刚体)组件可使游戏对象在物理系统的控制下来运动,刚体可接受外力与扭矩力用来保证游戏对象像在真实世界中那样进行运动。任何游戏对象只有添加了刚体组件才能受到重力的影响,通过脚本为游戏对象添加的作用力以及通过NVIDIA物理引擎与其他的游戏对象发生互动的运算都需要游戏对象添加了刚体组件。

个人理解就是刚体是用来模拟物体受到一个力作用时候的表现,这个从刚体中的参数就可以看出:

技术分享

全是关于物体受到力之后,怎么运动的参数,比如Mass质量,Drag阻力。


碰撞体的官方(摘自Unity3d的官方指导书《Unity4.x从入门到精通》)解释如下:

碰撞体是物理组件的一类,它要与刚体一起添加到游戏对象上才能触发碰撞。如果两个刚体相互撞在一起,除非两个对象有碰撞体时物理引擎才会计算碰撞,在物理模拟中,没有碰撞体的刚体会彼此相互穿过。


个人是这样理解的,为什么要判断碰撞,判断碰撞就是需要计算力,无论是阻力也好,动力也好,如果此时物体有刚体组件,那么物体就会在力的作用下运动。如果这个物体没有刚体,那么碰撞产生的力就没有任何意义了,那计算碰撞也就没有任何意义了。

所以,我们可以推断出,如果两个碰撞体都没有刚体组件,那么这两个物体即使相互发生了碰撞,那么也不会有碰撞事件的。


官网上的碰撞的图如下(注:据说是官网的图,我在网上很多地方看到了,但我目前为止还没找到在官网的哪个位置哈):

技术分享

从上面的图中我们看出来碰撞的双方中一定要有一个Rigidbody存在,并且碰撞双方必须都要有碰撞体组件。


但做实验的时候发现了一个很诡异的事情,就是发生碰撞的主体一定是要带刚体的,即只有带刚体的碰撞体去撞其他碰撞体时,双方才会收到碰撞事件,以下是我做的实验:

一、控制A(刚体加碰撞体)撞击 静止的B(只有碰撞体),双方能收到碰撞事件。

二、控制B(只有碰撞体)撞击 静止的A(刚体加碰撞体),双方收不到碰撞事件。

三、让A(刚体加碰撞体)自由下落,然后控制B(只有碰撞体)去撞击A,双方能受到碰撞事件。


得出的结论似乎是如果碰撞双方只有一个有刚体,那么那个刚体一定要处于运动的状态下才会有碰撞事件发生。


接下来就是IsTrigger选项了,上面的情况都没有触发信息,先列举一下触发事件和碰撞事件,如下:

 

触发信息检测:
1.MonoBehaviour.OnTriggerEnter( Collider other )当进入触发器
2.MonoBehaviour.OnTriggerExit( Collider other )当退出触发器
3.MonoBehaviour.OnTriggerStay( Collider other )当逗留触发器

碰撞信息检测:
1.MonoBehaviour.OnCollisionEnter( Collision collisionInfo ) 当进入碰撞器
2.MonoBehaviour.OnCollisionExit( Collision collisionInfo ) 当退出碰撞器
3.MonoBehaviour.OnCollisionStay( Collision collisionInfo )  当逗留碰撞器


 

下面是一张关于触发的关系图,如下(注:同样是来自网上,我目前还没在官网上找着哈)

技术分享


下面就是我做的测试情况,都是A物体去撞B物体。

一、A(碰撞体),B(没有碰撞体,无论有没有刚体),没有触发事件。

二、A(碰撞体),B(碰撞体),没有触发事件。

二、A(碰撞体和刚体,开启IsTrigger),B(碰撞体,关闭IsTrigger),双方都能收到触发事件。

三、A(碰撞体和刚体,关闭IsTrigger),B(碰撞体,开启IsTrigger),双方都能收到触发事件。

四、A (碰撞体,关闭IsTrigger),B(碰撞体和刚体,开启IsTrigger),没有触发事件。

五、A (碰撞体,开启IsTrigger),B(碰撞体和刚体,关闭IsTrigger),没有触发事件。


额外实验:

六、A(碰撞体和刚体,开启IsTrigger)自由下落,B(碰撞体)撞击A,双方都能收到触发事件。


根据上面的实验得出,如果要收到触发事件,必须满足如下三个条件:

1、必须都要有碰撞器组件(Collider),其实上面的碰撞事件同样也需要这个前提条件。

2、必须有一个物体带刚体组件,并且处于运动状体中(包括主动运动去撞击别人和在运动过程中被别人撞击)。

3、两个碰撞器中至少有一个开启了IsTrigger。


此外还有两点:

一、产生触发事件的两个物体会相互穿越,准确的说是因为开启IsTrigger那个物体会被物理引擎锁忽略掉,所以会产生两个物体穿越的情况。

二、两个对象要么都收到碰撞事件,要么都收到触发事件,不会出现一个收到触发事件,一个收到碰撞事件的情况。


还有一个经验点就是,在控制一个物体A去撞另一个物体B时,不要直接去修改物体A的Transform的position属性,因为你会发现如果即使两者发生了碰撞也还是会穿越的,原因就在于我们是直接设置的坐标,如果物体A有刚体组件的话,应该用AddForce,给物体添加一个力,然后让物理引擎去让物体动,此时如果发生了碰撞的话,就不会穿越了。


好吧,下午折腾了半天之后,我就一直在想那个IsTrigger有啥用,后来在网上搜了一下,说是可以做门的自动打开,就让我想起了Unity3d 4自带的哪个AngryBots例子,貌似当控制主角走到一个门前时,那个门会自动打开。

于是就打开那个例子工程,去看,发现果然是这样的,大概原理就是在门前面放了一个设置了IsTrigger的透明碰撞体,用于专门监听碰撞,当主角进入这个区域时,就通过OnTriggerEnter事件把门预先打开。

如图:

技术分享


转自:http://blog.csdn.net/monzart7an/article/details/22739421





























以上是关于Unity --- 物理引擎 --- 触发器 与 碰撞器详解的主要内容,如果未能解决你的问题,请参考以下文章

unity同一个gameobject上可以同时存在碰撞体和触发器吗

Unity之碰撞体组件

Unity3D使用时发现的问题及解决方法(触发碰撞条件)

Unity面试题整理

转载 unity3d 理解刚体(Rigidbody)和碰撞体(Collider)以及触发器(Is Trigger)

UNITY物理系统[Colliders]