好久没写帖子了,最近忙于个人私事与工事间的徘徊,so...,在此感谢大家一直以来对我的关注与支持,谢谢!!!


好了,就不多废话了,直接进入今天主题。


最近总有人问我

unity

3d中碰撞检测到底怎么做?什么时候该用触发信息检测碰撞?什么时候又该用碰撞信息检测碰撞?它们之间有什么区别?等等...ok,让我们带着上边疑问一起一探究竟吧。



首先,我们简单来了解下碰撞的定义:

如果两个或几个物体再相遇中,物体之间的相互作用力仅持续一个极为短暂的时间,这些现象就是碰撞。


由上可见,要产生碰撞信息必须满足2个以上的对象物体,其中一个一定包含”力“。


那么在unity,它又所需什么样的条件?


其实,在unity中我在此总结有3种方式8种方法,分别为:


1.通过触发器信息检测碰撞


   1).OnTriggerEnter( Collider other )进入触发器


   2).OnTriggerExit( Collider other )退出触发器


   3).OnTriggerStay( Collider other )停留触发器


2.通过碰撞信息检测碰撞


  

4).OnCollisionEnter( Collision collisionInfo ) 进入碰撞器


  5).OnCollisionExit( Collision collisionInfo ) 退出碰撞器


  6).OnCollisionStay( Collision collisionInfo )  停留碰撞器


3.通过Ray射线检测碰撞(感觉又不属于碰撞范畴,但是它又具有这样的功能,因此暂且归纳)


static function Raycast (origin : Vector3, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : bool


8).LayerMask层级检测


好了,我们知道了有这么多种在unity中检测碰撞的方式及方法,可是如何去使用呢?


so,我们有必要稍微了解下它们的基本概念:


1.碰撞器:在unity中,所谓的

碰撞器其实是一些组件 ,同时包含了Box Colloder(盒子状)、Sphere Collider(球形)等,如图

 



2.触发器:在unity中,是建立在碰撞器基础上的,也就是在

碰撞器的属性面板中勾选IsTrigger选择框 即可,如图


 



3.Ray射线:它不是Unity特有的东西,至于还有那些地方应用,在此我就不过多描述,不在业务范围内,有兴趣的可以自行去研究下。


在unity中它是

由一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射 。


因此在unity中应用还是非常广泛的,通常能快速解决一些棘手的

问题

,如:点击屏幕移动角色,在3维空间中不使用控件的前提下,点击选中某个对象等等...如图


 




ok,上面我们基本了解了各种方式的基本概念,下面举个列子详细讲解下。


新建一个场景,在此名字为test,加一个平行光,然后依次创建cube、Capsule、Sphere 三个对象,接着继续创建3个材质球(

Material ),


分别为cube

Material、 Capsule Material 、Sphere Material并给3种不同颜色:红、黄、蓝 。建好如下图  


 




1.创建代码TriggerTest ,如下

纯文本查看  复制代码


         using 
          UnityEngine; 
        
 
         using 
          System.Collections; 
        

            
        
 
         public 
          class 
          TriggerTest : MonoBehaviour { 
        
 
                  
         void 
          OnTriggerEnter( Collider other ) 
        
 
              
         { 
        
 
                  
         Debug.Log(other.name+ 
         "通过触发器信息检测碰撞进入" 
         ); 
        
 
              
         } 




代码写好后,绑定脚本到红色Cube上运行,手动在Scene拖动任意其他对象去跟Cube碰撞,尴尬的事情来了,居然没有任何反应


这是什么情况?嘿嘿,看来我们还得完善下unity中有关碰撞器方面的知识啊,以下来自圣典翻译文档(蛮牛不会认为我打广告吧,为学东西拼啦)


 



Static Collider 静态碰撞器、 Rigidbody Collider 刚体碰撞器、

Kinematic Rigidbody Collider 运动学刚体碰撞器这三种为常用类型,


其中, 这三种碰撞器如果勾选了IsTrigger复选框,就变成了相应的触发器。


还有个 表里面包含了检测到碰撞信息所必要的碰撞组合,总结很到位


 



从表中可以看出,两个碰撞器要想检测到碰撞信息,至少有一个是Rigidbody Collider。这个就是我们刚才失败的关键


原来还有一个东西我们忘记了,那就是 Rigidbody(钢体)

,ok,我们给红色的cube 加上钢体,去掉Use Gravity勾选,这里


我们不需要使用重力,运行,移动黄色胶囊去碰撞红色cube


 



ok,是我们想要的结果。


简要终结下: 两个GameObject发生碰撞,要想检测到触发信息,最少要有一个刚体碰撞器并且勾选了IsTrigger复选框,另一个最少要有一个碰撞器组件,此时检测碰撞的脚本必须附加在那个带有刚体的触发器上。



可是,后面自己又测试一番下来 发现一个很奇怪的问题,触发器一直是红色Cube


1.我把钢体绑定到其他物体上,运行结果,只有cube去撞其他物体才能触发,手动拖动其他物体不触发。


2.接着我把脚本放到其他物体上,运行结果同上。


3.然后我把脚本放到其他物体上,钢体放红色Cube上,运行结果,只有手动拖动其他物体去撞cube触发,拖动cube去撞其他物体不触发。



剩下的 通过碰撞信息检测碰撞大家自行研究,在此我就不过多叙述,基本跟上同理,只不过不勾选Is Trigger就可以了,代码方法都换成 

OnCollision xxx  的就可以了,不要忘记里面参数也要换 Collision collisionInfo  。


最后大家可能会问,着2种都是碰撞检测 在什么情况下用哪个呢?


我只说 使用Collision碰撞信息检测碰撞 是属于物理碰撞,如何使用 就看大家使用时是否需要具有物理特性碰撞了,没有就用Trigger触发保险点。


这里是圣殿的翻译文档地址也给大家,方便查看 :http://game.ceeger.com/Components/class-MeshCollider.html



接下来就是Ray射线检测及关于 layerMask的使用

,这块在我前面帖子有专门的讲解【 unity射线碰撞检测+LayerMask的使用   】大家可以看下。


其实,这里我最想说的是关于Physics.Raycast()的用法,以前其实我自己都没注意这块,今天无意间发现原来里面还有这么多方便使用的函数


其中,包括 通过范围来查找怪物

等等,下面奉上 Physics.xx 函数方法


1) static   function  Raycast (origin :  Vector3 , direction :  Vector3 , distance :  float  =  Mathf.Infinity , layerMask :  int  = kDefaultRaycastLayers) :  bool


在origin坐标上建立一个方向为direction,距离为distance的射线,可以与layerMask(层遮罩)之外的所有的collider碰撞;


返回true如果碰撞到任何物体,否则返回false。 distance默认为无限远,layerMast默认为kDefaultRaycastLayers


只与第一个接触到的物体产生碰撞。


static   function  Raycast (origin :  Vector3 , direction :  Vector3 , out hitInfo :  RaycastHit , distance :  float  =  Mathf.Infinity , layerMask :  int  = kDefaultRaycastLayers) :  bool


多了一个out hitInfo: RaycastHit, 如果碰撞到物体,具体碰撞数据和被碰撞体都会被记录在RaycastHit上,包括碰撞位置,碰撞位置法线,被碰撞体的Transform节点等信息。其他一样。


脚本:


var explosionPosition: Vector3;


var hit: RaycastHit;


if(Physics.Raycast(transform.position,target.position,hit,100)){


explosionPosition=hit.point;


}


static   function  Raycast (ray :  Ray , distance :  float  =  Mathf.Infinity , layerMask :  int  = kDefaultRaycastLayers) :  bool


static   function  Raycast (ray :  Ray , out hitInfo :  RaycastHit , distance :  float  =  Mathf.Infinity , layerMask :  int  = kDefaultRaycastLayers) :  bool


直接由一个射线ray来指示位置和方向。其他一样。


2) static   function  RaycastAll (ray :  Ray , distance :  float  =  Mathf.Infinity , layerMask :  int  = kDefaultRaycastLayers) :  RaycastHit []


static   function  RaycastAll (origin :  Vector3 , direction :  Vector3 , distance :  float  =  Mathf.Infinity , layermask :  int  = kDefaultRaycastLayers) :  RaycastHit []


与所有在ray这条射线上的物体碰撞并返回所有被碰撞体,RaycastHit[]。 其他同RaycastAll一样。


3)static   function  Linecast ( start  :  Vector3 , end :  Vector3 , layerMask :  int  = kDefaultRaycastLayers) :  bool


static   function  Linecast ( start  :  Vector3 , end :  Vector3 , out hitInfo :  RaycastHit , layerMask :  int  = kDefaultRaycastLayers) :  bool


从start到end画一条直线,其他与Raycast和RaycastAll类似。 这个通常可以用于检测AI是否能看到目标物体等功能。


4) static   function  OverlapSphere (position :  Vector3 , radius :  float , layerMask :  int  = kAllLayers) :  Collider []---可用于检查范围内的怪物


检测在position位置的半径radius的球形范围内是否存在可碰撞体并返回所有检测到的collider


5) static   function  CheckSphere (position :  Vector3 , radius :  float , layerMask :  int  = kDefaultRaycastLayers) :  bool


当任何物体碰到position位置的半径为radius的球形范围时返回true;


6) static   function  CheckCapsule ( start  :  Vector3 , end :  Vector3 , radius :  float , layermask :  int  = kDefaultRaycastLayers) :  bool


当任何物体碰到定义的胶囊体范围时返回true;


7)  static   function  IgnoreCollision (collider1 :  Collider , collider2 :  Collider , ignore :  bool  = true) :  void


控制collider1和collider2 是否可以碰撞。 ignore=true 两者将不会计算是否碰撞, ignore=false 则计算两者是否有碰撞。