(转)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方面的碰撞,这里面包含摄像头的碰撞检测,并且会以这个官方的工程作为试验平台,敬请期待。
(转)Unity3d中的碰撞检测的更多相关文章
- unity3d中 刚体(Rigidbody) 碰撞体(Collider) 触发器(Is Trigger)
刚体(Rigidbody)的官方(摘自Unity3d的官方指导书<Unity4.x从入门到精通>)解释如下: Rigidbody(刚体)组件可使游戏对象在物理系统的控制下来运动,刚体可 ...
- 关于Unity中的碰撞检测和管理(2D)
创建Unity3D项目和Unity2D项目的区别. 1.3D项目有摄像机和太阳光,2D项目只有摄像机 2.3D项目使用的贴图类型是Texture纹理,2D项目使用的贴图类型是Sprite 2D/UI ...
- 【Unity3d游戏开发】Unity3D中的3D数学基础---向量
向量是2D.3D数学研究的标准工具,在3D游戏中向量是基础.因此掌握好向量的一些基本概念以及属性和常用运算方法就显得尤为重要.在本篇博客中,马三就来和大家一起回顾和学习一下Unity3D中那些常用的3 ...
- Unity3D中可中途释放的单例
Unity3D中可中途释放的单例 使用静态类,静态变量的坏处是从程序加载后就一直占用内存,想要释放比较麻烦,可是之前使用的单例,没有提供释放的方法,那是不是也同静态的一样直到程序结束菜释放?那单例的好 ...
- 图文详解Unity3D中Material的Tiling和Offset是怎么回事
图文详解Unity3D中Material的Tiling和Offset是怎么回事 Tiling和Offset概述 Tiling表示UV坐标的缩放倍数,Offset表示UV坐标的起始位置. 这样说当然是隔 ...
- Unity3D中Update()与FixedUpdate()的区别
Unity3D中Update()与FixedUpdate()的区别是什么呢?从字面上理解,它们都是在更新时会被调用,并且会循环的调用.但是Update会在每次渲染新的一帧时,被调用.而FixedUpd ...
- Unity3D中C#和js方法相互调用
通过查找资料,Unity3D中C#和js要相互调用彼此的方法,js文件必须放在"Standard Assets". "Pro Standard Assets" ...
- 在unity3d中使用opencv
1.首先下载opencv2.4.10,解压缩后放在合适的地方,然后根据自己的电脑(32位或64位)选择X86或X64,我的是32位,将“opencv存放路径\build\x86\vc12\bin”加入 ...
- Unity3D 中 用quaternion 来对一个坐标点进行旋转的初步体会
在unity3d中,用四元数来表示旋转,四元数英文名叫quaternion . 比如 transform.rotation 就是一个四元数,其由四个部分组成 Quaternion = (xi + yj ...
随机推荐
- 在eclipse中查看Android源码
声明:高手跳过此文章 当我们在eclipse中开发android程序的时候.往往须要看源码(可能是出于好奇,可能是读源码习惯),那么怎样查看Android源码呢? 比方以下这样的情况 图1 如果我们想 ...
- .Net Discovery系列之四 深入理解.Net垃圾收集机制(下)
上一节给大家介绍了 .Net GC的运行机制,下面来讲下与GC相关的重要方法. 第二节.GC关键方法解析 1.Dispose()方法 Dispose可用于释放所有资源,包括托管的和非托管的,需要自己实 ...
- AutoMapper在MVC中的运用03-字典集合、枚举映射,自定义解析器
本篇AutoMapper使用场景: ※ 源字典集合转换成目标字典集合 ※ 枚举映射 ※ 自定义解析器 ※ 源中的复杂属性和Get...方法转换成目标属性 源字典集合转换成目标字典集合 □ Domain ...
- SpringBoot 中使用 @Value 为 static 变量赋值
原文:https://www.jianshu.com/p/ea477fc9abf7 例如: public class Utils { @Value("${test.host}") ...
- Odoo进销存(采购、销售、仓库)入门教程 - 下
转帖地址:http://blog.csdn.net/wangnan537/article/details/46475105 2. 进销存实务 2.1 销售产品 李逍遥接到客户苏州美尚邻里超市购买10只 ...
- UIScrollView的判断位置的属性如下:
contentSize:CGSize类型,scrollview可以滑动的区域,例如,一个view的frame为(0,0,320,480),而scrollview的contentSize为(320,10 ...
- __NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance
同样是删除cell问题,帮我看看问题出现在哪,谢谢! 我的类文件myFile是继承UIViewController的(目的是为了能够在一个view里切换不同的tableView),在myFile.h中 ...
- 【linux】linux下shell命令 多个变量在命令中的引用 以及重新赋值给新的变量
原本的find命令: find /apps/Devops/jenkins/workspace/swapping/target/ -name '*swapping*.jar' 错误的命令: SOURCE ...
- go1.8之安装配置具体步骤
操作系统: CentOS 6.9_x64 go语言版本: 1.8.3 安装go 这里直接安装二进制,其它方式请自行搜索. 1.下载并安装go 命令如下: ? 1 2 3 wget https://st ...
- 《精通Oracle SQL(第2版) 》
<精通Oracle SQL(第2版) > 基本信息 作者: (美)Karen Morton Kerry Osborne Robyn Sands Riyaj Shamsud ...