纳金网

标题: Unity3d中的碰撞检测(一) [打印本页]

作者: wyb314    时间: 2012-10-30 23:49
标题: Unity3d中的碰撞检测(一)
  很多时候,当我们的主角与其他GameObject发生碰撞时, 我们需要做一些特殊的事情,比如:子弹击中敌人,敌人就得执行一系列的动作。这时,我们就需要检测到碰撞现象,即碰撞检测。这一篇,我来具体谈谈自己所了解的碰撞检测,希望高手不佞赐教。

    首先,我们得明确一点:即产生碰撞信息所需要的条件。事实上,在Unity3d中,能检测碰撞发生的方式有两种,一种是利用碰撞器,另一种则是利用触发器。这两种方式的应用非常广泛。为了完整的了解这两种方式,我们必须理解以下概念:
    (一)碰撞器是一群组件,它包含了很多种类,比如:Box Collider,Capsule Collider等,这些碰撞器应用的场合不同,但都必须加到GameObjecet身上。
    (二)所谓触发器,只需要在检视面板中的碰撞器组件中勾选IsTrigger属性选择框。
    (三)在Unity3d中,主要有以下接口函数来处理这两种碰撞检测:

触发信息检测:
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 )  当逗留碰撞器


以上这六个接口都是MonoBehaviour的函数,由于我们新建的脚本都继承这个MonoBehaviour这个类。所以我们的脚本里面可以覆写这六个函数。

下面让我举一个例子来详细讲解这几个函数的作用:

        首先,为了使讲解更特别一些,我们就以官方的一个例子为平台,深刻讲解碰撞检测这个知识点,此例子的下载链接如下:http://unity3d.com/support/resources/example-projects/shadowdemo


我们下载完此Demo之后,解压它,并用Unity打开它。我们在Project面板中找到Apartment Scene场景,打开它眼前的画面非常精美:







还有更牛的,单击“运行按钮”,试着用鼠标捡起里面的桌椅,你可以向其他地方砸去,此时,你会惊奇的发现,好像真的一般,桌子可以与椅子或者墙面发生碰撞,因此,我们可以建立两个Cube来测试我们的碰撞检测。但我们一开始却不用这个场景来作测试,我们必须弄清楚几件事情。
        首先,我们在这个工程中新建一个场景,取名为:TestCollision。然后在Project面板中新建两个文件夹,分别取名为Materials和CustomScripts。接着,我们在Materials中新建三个材质球:Cube1,Cube2,Plane,并分别给他们三种不同的颜色。    在CustomScripts文件夹下新建一个C#脚本,取名为:TestCollider。接下来,我们在场景中建立三个GameObject:Cube1,Cube2,Plane,如下图:








其中绿色的中方体是Cube1,蓝色的是Cube2,黄灰色的是Plane。至此,我们最初的测试场景就搭建好了,下面,我们来编写脚本来验证我们的推断了。首先,我们验证一下碰撞检测。TestCollider代码如下:


using UnityEngine;
using System.Collections;

public class TestCollider : MonoBehaviour {
    public Transform cube;//将要碰撞到的GameObject的transform
    public float speed = 1.0f;
    public Vector3 dir = Vector3.zero;

    void Start() {
        if(cube){
            dir = cube.position - transform.position;
            dir = dir.normalized;
        }
      
    }
    void Update() {






        transform.Translate(dir * Time.deltaTime * speed);
   
    }

    void OnCollisionEnter(Collision collisionInfo)
    {
        Debug.Log("碰撞到的物体的名字是:" + collisionInfo.gameObject.name);
    }
}


将Cube2从Hierarchy面板上拖拽到脚本中的Cube选项中。
这段代码并不难理解,就是Cube1一直向右移动时与Cube2发生碰撞产生碰撞信息,打印碰撞到的物体的名字。

    可现实总是那么的残酷,这个碰撞信息就一直没打印出来。哎,到底问题出在哪呢?这时,我们就需要完善的了解一下有关碰撞器方面的知识啊。我把我们还得了解的概念列举如下:
1.Static Collider 静态碰撞器
指的是没有附加刚体而附加了碰撞器的游戏对象。这类对象会保持静止或很轻微的移动。这对于环境模型十分好用,比如刚体和墙面碰撞时而不会移动。

2.Rigidbody Collider 刚体碰撞器
指的是附加了刚体和碰撞器的游戏对象。

3.Kinematic Rigidbody Collider 运动学刚体碰撞器
在第2点得基础上勾选了刚体组件中的IsKinematic属性,如果要移动这类对象,就只能修改它的Transform,而不是用力。这类游戏对象还有许多其他的独特的使用情景。
这三种碰撞器如果勾选了IsTrigger复选框,就变成了相应的触发器了。

这是我在文档上截下来的一个图,如果读者觉得英文看起来吃力的话,就可以到Unity圣典上去看翻译的文档。







这个表里面包含了检测到碰撞信息所必要的碰撞组合:从表中可以看出,两个碰撞器要想检测到碰撞信息,至少有一个是Rigidbody Collider。这个就是我们刚才失败的关键。我们回到Unity编辑器中,验证一下我们的猜想。我们先给Cube1添加刚体组件。没想到控制台打印了如下语句:






不过,这也是必须的,那么,我们将刚体组件附加在Cube2而不是Cube1上呢?我们发现,控制台上没有打印任何语句,此时,我们可以得出如下结论:两个物体发生碰撞,如果要检测到碰撞信息,那么其中必有一个物体既带有碰撞器,又带有刚体,且检测碰撞信息的脚本必须附着在带有刚体的碰撞器上。

到此我们就可以结束碰撞信息的检测了,剩下的2个函数就由读者自行验证一下。下面我们来验证触发信息检测。我们新建一个脚本,代码如下:

using UnityEngine;
using System.Collections;

public class TestCollider : MonoBehaviour
{
    public Transform cube;
    public float speed = 1.0f;
    public Vector3 dir = Vector3.zero;

    void Start() {
        if (cube)
        {
            dir = cube.position - transform.position;
            dir = dir.normalized;
        }
    }


    void Update() {

        transform.Translate(dir * Time.deltaTime * speed);
   
    }

    void OnTriggerEnter(Collider other)
    {
        Debug.Log("碰撞到的物体的名字是:" + other.gameObject.name);
    }
}


我们设置Cube1为刚体碰撞器(注意,此时得将刚体组件中的Use Gravity复选框的勾选去掉 ),然后勾选碰撞器组件中的Is Trigger复选框。然后我们将此脚本拖拽到Cube1上面,然后将Cube2从Hierarchy面板上拖拽到脚本中的Cube选项中。运行一下,果然有成功了:




此时,我们将脚本拖给Cube2而不拖给Cube1时,我们的结果和上次一样,没有检测到触发信息。因此,我们可以得出这样一个结论:两个GameObject发生碰撞,要想检测到触发信息,最少要有一个刚体碰撞器并且勾选了IsTrigger复选框,另一个最少要有一个碰撞器组件,此时检测碰撞的脚本必须附加在那个带有刚体的触发器上。

至此,触发信息的检测我们也实现了。剩下的两个函数留给读者自行验证。但是,由于两组函数中的参数的类型不同,我们可以通过这些参数得到一些信息。比如OnTriggerEnter,里面的参数类型是:Collision,根据这个参数,我们可以求得一些东西,比如接触点,具体可以看API文档关于Collision这一章,里面有一个变量contacts。又比如
OnTriggerEnter这个函数,参数类型为:Collider。我们可以 取得这个对象的shareMaterial这个属性,也就是物理材质。
    现在我们可以打开刚才那个官方的场景,可以在那些个刚体上绑定一个碰撞检测的脚本,然后就可以用鼠标让它与其他物体进行碰撞,可以从控制台上打印碰撞到的物体的名字。好了,23点了,困了,下一篇,我会介绍LayerMask方面的碰撞,这里面包含摄像头的碰撞检测,并且会以这个官方的工程作为试验平台,敬请期待。





作者: 艾西格亚    时间: 2012-10-31 00:25
感谢精彩的文章分享!

作者: may    时间: 2012-11-5 00:57
过来学习学习
作者: .    时间: 2012-11-8 21:15
这是一个好帖子,大家快来围观!!

作者: 狂风大尉    时间: 2012-11-11 00:41
很好的教程与分析,顶起!!

作者: 娃娃儿    时间: 2013-1-7 22:43
很不错,解释了为什么我做的碰撞时而生效时而不生效的,这下灵光了
作者: 查穆    时间: 2013-3-9 11:29
官网的这个例子找不到了,求个连接。

作者: Sora    时间: 2013-3-20 19:18
清晰明瞭的好教學呢 ~~~

作者: 如来佛祖    时间: 2013-4-12 11:00
倒数第二段的这里写错了哦,比如OnTriggerEnter(这里应该是OnCollisionEnter,里面的参数类型是:Collision,根据这个参数,我们可以求得一些东西,比如接触点,具体可以看API文档关于Collision这一章,里面有一个变量contacts。
楼主加油~~~
作者: 如来佛祖    时间: 2013-4-12 11:03
之前一直不太清晰,这下清晰了很多呢,楼主加油,我很期待你~~~
作者: fcczhfgs    时间: 2013-4-13 09:42
很不错的分析,这个是必须掌握的知识点,不然会相当郁闷
作者: wyb314    时间: 2013-4-15 23:10
如来佛祖 发表于 2013-4-12 11:00
倒数第二段的这里写错了哦,比如OnTriggerEnter(这里应该是OnCollisionEnter),里面的参数类型是:Collis ...

触发器碰撞检测,区别于碰撞器检测。
作者: 走四方    时间: 2013-5-28 16:35
很好~~~~~~~~~~~~~~~~~
作者: 走四方    时间: 2013-5-28 17:30
感谢楼主分享!!!!!!!
作者: zyj337    时间: 2013-7-2 19:00
谢谢楼主的教程,明天继续学习
作者: nanwumi    时间: 2013-7-7 17:12
感谢分享
作者: shengbin88    时间: 2013-8-15 15:25
写教程不易,顶撒
作者: alexlam127    时间: 2013-8-15 16:02

这个要来试试了,学习!

作者: chana1101    时间: 2013-9-2 21:47
很好,搞明白了碰撞器的用法
作者: shotdead    时间: 2013-9-12 00:36
谢谢分享.!
作者: xxj123    时间: 2013-9-13 10:06
不错的资源,谢谢分享
作者: 毛毛虫    时间: 2013-9-24 11:03
好文章,写的太详细了,厉害!
作者: herry7x    时间: 2013-9-24 13:56
这个文章真的不错,我就是参考这个文章做出来的碰撞系统。
作者: lingernow    时间: 2013-9-25 00:32
最近在學習賽車遊戲 正需要碰撞的分析呢
謝謝樓主分享
作者: zoeyun520    时间: 2013-9-25 09:02
好文章,多谢分享,学习了
作者: vzheng    时间: 2013-11-20 10:00
感谢分享!
对了 继承的方法叫做: 重写。加油!
作者: 宁唯是宁唯    时间: 2013-12-26 15:41
之前一直不太清晰,这下清晰了很多呢,楼主加油,我很期待你
作者: nianhua2008    时间: 2013-12-27 15:12
好,学习了!
多谢分享!
作者: qwer4650987    时间: 2013-12-27 15:51
物理效果是一个比较重要的东西
作者: qwer4650987    时间: 2013-12-27 15:51
unity3D中自带的和代码实现有什么区别
作者: 迷失深蓝    时间: 2014-1-25 21:54
感谢楼主!!!!
作者: tangqizuse    时间: 2014-2-20 23:35
新人学习,谢谢分享
作者: 鸡贼不差钱    时间: 2014-2-26 15:26
好贴,感谢分享,学习中!!!
作者: 鸡贼不差钱    时间: 2014-3-14 11:35
感谢楼主,很有用
作者: 猫咪    时间: 2014-3-14 11:51
教程不错,倾清晰的
作者: 灵魂重新    时间: 2014-3-26 13:23
有一点写错了,两个碰撞器,其中一个为刚体,用检测脚本都能检测到的,我亲自试过
作者: shiyoi    时间: 2014-4-6 15:12
zhichi yige
作者: shiyoi    时间: 2014-4-6 15:12
支持一个
作者: hxcspitfire    时间: 2014-4-6 15:37
感谢精彩的文章分享!
作者: D的意志    时间: 2014-7-13 12:49
感谢分享。。。
作者: yuyu8823    时间: 2014-7-15 10:42
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
作者: abiaocom    时间: 2015-1-2 11:03
好文章啊,谢谢楼主分享
作者: tianhett    时间: 2015-1-2 12:25
感觉Collision碰撞很少用到。。。。大多时候都是在用Trigger碰撞的。。。。
作者: hcjamm    时间: 2015-1-4 06:23
很好的文章,感谢
作者: zxc0254    时间: 2015-1-14 08:19
不错的贴子  赞一个
作者: jayt1001    时间: 2015-11-4 11:37
这是一个好帖子
作者: lichao545    时间: 2016-1-11 15:06
艾西格亚 发表于 2012-10-31 00:25
感谢精彩的文章分享!

大神,这帖子的图咋都刷新不出来呢???
作者: haruppwing    时间: 2016-1-11 22:01
謝謝版主分享




欢迎光临 纳金网 (http://www.narkii.com/club/) Powered by Discuz! X2.5