好久没写帖子了,最近忙于个人私事与工事间的徘徊,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 则计算两者是否有碰撞。