Unity3D检测(碰撞、射线)

好久没写帖子了,最近忙于个人私事与工事间的徘徊,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射线检测碰撞(感觉又不属于碰撞范畴,但是它又具有这样的功能,因此暂且归纳)
  7).static function Raycast (origin : Vector3direction : Vector3distance : float = Mathf.InfinitylayerMask : 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 ,如下
[C#]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
using UnityEngine;
using System.Collections;
 
public class TriggerTest : MonoBehaviour {
         void OnTriggerEnter( Collider other )
     {
         Debug.Log(other.name+ "通过触发器信息检测碰撞进入" );
     }
     void OnTriggerExit( Collider other )
     {
         Debug.Log(other.name + "通过触发器信息检测碰撞退出" );
     }
     void OnTriggerStay( 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 则计算两者是否有碰撞。

原文地址:http://www.cnblogs.com/tonge/p/3614414.html 是不是挺有用?那还不赶快动手尝试下?
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值