1.2 触发器事件
知道了物体如何移动,下一步就得知道如何判断一个物体是否碰到了另一个物体,这也是绝大部分游戏都需要用到的功能。例如,在经典游戏PONG中,球碰到边界和挡板会反弹;《超级马里奥兄弟》中的马里奥碰到蘑菇就会变大。
实际上,抛开高级游戏引擎提供的各种技术,直接判断物体之间的距离就足以实现碰撞检测,即两个物体之间的距离小于某个值,就是碰到了。早期的游戏就是这么做的,即便在今天,对某些需要特别优化的功能也可以用这种方法。
不过Unity等现代游戏引擎给出了更统一、更简便的方法——使用触发器。
触发器是一个组件,它定义了一个范围。当其他带有碰撞体组件的物体进入了这个范围时,就会产生一个触发事件,脚本捕捉到这个事件的时候,就可以做出相应的处理。
1.2.1 创建触发器
在之前的小球旁边创建一个立方体。创建的立方体已经自带碰撞体,即Box Collider,可以在Inspector窗口中看到,默认该碰撞体的范围就是立方体的范围,如图1-10所示。
图1-10 立方体的Box Collider组件
在Unity中,触发器和碰撞体共用了同一种组件——Collider,实际上两者是不同的概念。勾选Box Collider面板中的Is Trigger选项,碰撞体就变成了同样外形的触发器,如图1-11所示。
图1-11 勾选Box Collider组件的Is Trigger选项
并不是任何物体进入触发器的范围都会产生触发事件。产生触发事件的具体要求将在第3章物理系统中进行讨论。这里需要做的是,给小球添加一个Rigidbody(刚体)组件,并勾选Is Kinematic(动力学)选项,其他选项不重要,如图1-12所示。
图1-12 勾选Rigidbody组件的Is Kinematic选项
做完以上步骤,碰撞的场景设置就完成了,接下来讲解如何编写脚本来处理触发事件。
1.2.2 触发器事件函数
碰撞和触发总是发生在两个物体之间,所以根据不同情况,可以选择其中一个物体进行碰撞或触发的处理。当前按照常规思路,被碰到的物体应该是立方体,因此给立方体新建一个脚本并挂载,取名Coin,用于处理碰撞。
触发事件实际上有3种,即开始触发(OnTriggerEnter)、触发持续中(OnTriggerStay)及结束触发(OnTriggerExit),分别代表另一个物体进入触发范围、在触发范围内、离开触发范围这3个阶段。这里只介绍开始触发事件,Coin脚本内容如下。
using UnityEngine; public class Coin : MonoBehaviour { // 触发开始事件OnTriggerEnter,参数为碰撞体信息,即另一个 进入了该触发区域的物体的碰撞体 private void OnTriggerEnter(Collider other) { Debug.Log(other.name + " 碰到了我"); } }
小提示
删除不必要的事件函数
可以看到左边代码里不必要的Start()函数、Update()函数等已经通通删除了。这是一种良好的编码习惯,可以减少不必要的函数执行。即使是函数体为空的函数,执行时依然会消耗CPU资源。
以上代码会接收到其他碰撞体进入触发区域的事件,且能获得该碰撞体的信息。上面的代码利用other.name输出了进入触发范围的物体名称。
现在运行游戏进行测试。测试方法是先运行游戏,再直接在场景窗口中拖曳球体,让它和立方体接触,然后观察Console窗口是否出现了消息提示,如图1-13所示。
图1-13 物体接触触发了OnTriggerEnter事件
可以看到,触发时Console窗口输出了消息,而且获得了物体名称Sphere。
1.2.3 实例:吃金币
通过控制物体的运动和触发器,很容易做出游戏中吃金币和金币消失的效果,下面就来实际操作一下。
01 为更好地测试,先在前面例子的基础上调整镜头位置,变成俯视角投。操作方法提示:摄像机位置归0,沿x轴转90°,然后适当沿y轴升高。摄像机的参考位置和旋转角度如图1-14所示。
图1-14 设置俯视角时摄像机的位置和角度
02 新建球体,位置归0。挂载之前用过的Ball脚本,然后添加Rigidbody组件,并勾选Is Kinematic选项,与第1.2.1小节设置相同。
03 新建立方体,位置归0,向右平移摆放到球体旁边。
04 为了让“金币”更醒目,给立方体添加一个金黄色材质。先在Project窗口中新建一个Material(材质),如图1-15所示。
图1-15 创建材质
05 将材质命名为matCoin,如图1-16所示。
图1-16 给材质重命名
06 选中新建的材质,在Inspector窗口中将它的颜色修改为明亮的黄色,如图1-17所示。
图1-17 修改材质的颜色
07 将材质文件直接拖曳到场景中的立方体上,立方体就变成了黄色。这时选中立方体,在Inspector窗口中可以看到材质名称已经变为matCoin了,如图1-18所示。
图1-18 给物体指定材质
完成以上操作后,在Game窗口中看到的效果如图1-19所示。
图1-19 吃金币场景搭建完成
由于球体已挂载了之前的Ball脚本,因此可以根据输入进行移动。注意立方体要勾选Is Trigger选项,并挂载Coin脚本,设置与1.2.1小节相同。
由于金币被碰撞到以后就应该消失,因此修改的Coin脚本如下。
using UnityEngine; public class Coin : MonoBehaviour { // 触发开始事件OnTriggerEnter,参数为碰撞体信息,即另一个进入了该触发区域的物体的碰撞体 private void OnTriggerEnter(Collider other) { Debug.Log(other.name + " 碰到了我"); // 销毁自己 Destroy(gameObject); } }
此处仅添加了一个Destroy()函数调用,该函数用于销毁物体,而参数gameObject指代的正是脚本所挂载到的物体。如何从物体找到组件,如何从组件找到物体,这些都会在第2章中详细讲解。
测试游戏,用键盘控制小球,检查小球碰到立方体后,立方体是否消失。
如果测试正常,就可以多复制几个立方体。选中立方体,按Ctrl+D快捷键就可以复制立方体,然后调整位置,如图1-20所示。
图1-20 复制多个金币物体并测试
如果读者阅读到了这里,且跟着指引完成了演示案例,那么就能明白编写脚本的基本流程,并理解移动、碰撞等基本操作中每一句代码的含义。如此一来,利用这些知识就能制作一个相对完整的小游戏了。