本节书摘来异步社区《Unity 5.x游戏开发实战》一书中的第2章,第2.7节,作者: Alan Thorn 译者: 李华峰 责编: 胡俊英,更多章节内容可以访问云栖社区“异步社区”公众号查看。###2.7 庆典和焰火
至此,金币采集游戏几乎要完成了。金币可以被采集了,计时器也开始工作了,但是胜利的条件却没有得到妥善的处理。当玩家在计时器中的时间耗尽之前采集到所有的金币,游戏中并没有任何胜利的提示。相反倒计时仍然会继续,就好像胜利的条件完全没有达到一样。下面来解决这个问题,首先,当游戏者在游戏中获得胜利之后,应该删除计时器对象,以防止倒计时继续进行,并给出一些视觉上的效果来提示玩家该关卡已经完成。在这种情况下,可以添加一些焰火(Fireworks)。从Unity 5的例子系统包(Particle System Packages)即可添加焰火,操作方法为:依次选中“Standard Assets | ParticleSystems | Prefabs folder”,然后将焰火粒子系统(Fireworks Particle System)拖曳到场景中,可以继续添加2到3个焰火粒子系统,如图2.29所示。
默认情况下,所有的焰火粒子系统都会在关卡一开始时执行。可以通过在工具栏上单击“Play”按钮来测试这个游戏。不过这并不是所希望的效果,我们所设计的效果应该是当游戏者达成胜利条件以后,才执行这个焰火的特效。在场景中选中焰火粒子系统对象,然后在对象的 Inspector 面板上取消组件“Particle System”上单选框“Play On Awake”的选中状态,取消“Play On Awake”的功能,如图2.30所示。
取消“Play On Awake”之后,粒子系统就不会在关卡开始的时候自动执行了。这是正确的,但是这些粒子系统在整个游戏中都不会执行了,应该在合适的时候启动这些粒子系统,通过代码的编写就可以实现这一点。在进行编码之前,首先将全部的焰火对象都赋予一个合适的标签。这样做的原因是,在代码中需要在场景中查找全部的焰火对象,然后触发对应的事件。为了将焰火对象和其他对象区分开,可以使用Tag属性。所以,首先创建一个新的焰火Tag,然后将它们分配给场景中的焰火对象。在这一章开始的时候就为了检测是否与硬币发生碰撞为游戏中的角色添加过Tag属性,如图2.31所示。
现在所有的焰火对象都已经被添加了Tag了,接下来可以重新定义Coin.cs脚本类来处理场景中的胜利条件,如下面的代码示例2.7所示。
代码示例2.7:
//-------------------------
using UnityEngine;
using System.Collections;
//-------------------------
public class Coin : MonoBehaviour
{
//-------------------------
public static int CoinCount = 0;
//-------------------------
// 初始化函数
void Awake ()
{
//创建对象并增加金币的数量
++Coin.CoinCount;
}
//-------------------------
void OnTriggerEnter(Collider Col)
{
//当玩家采集到金币之后要销毁这个金币对象
if(Col.CompareTag("Player"))
Destroy(gameObject);
}
//-------------------------
void OnDestroy()
{
--Coin.CoinCount;
//检查剩余金币的数量
if(Coin.CoinCount <= 0)
{
//玩家收集完全部金币,游戏胜利
/销毁计时器对象,启动庆祝焰火
GameObject Timer = GameObject.Find("LevelTimer");
Destroy(Timer);
GameObject[] FireworkSystems =
GameObject.FindGameObjectsWithTag("Fireworks");
foreach(GameObject GO in FireworkSystems)
GO.GetComponent().Play();
}
}
//-------------------------
}
//-------------------------
下面对代码示例2.7进行总结。
- OnDestroy()函数是十分重要的,当一个金币被采集之后就会调用这个函数,它有一个用来判断是否全部金币都被收集(获胜条件)的if语句。
当获胜条件达成之后,系统就会调用函数GameObject.Find来寻找所有名为- LevelTimer的活动对象。如果找到了符合条件的对象,这个对象就会被删除。这通常发生在玩家已经在当前关卡取得胜利的情况下,需要删除计时器以防止它继续倒计时。如果场景中包含了多个符合条件的对象,那么该函数只会返回第一个对象。所以在同一个场景中只能有一个计时器。
注意
需要注意的是,要尽可能避免使用GameObject. Find()这个函数,它的执行效率很低。相对而言,FindGameObjects WithTag()函数是一个更好的选择。在这里介绍Game Object.Find的目的主要是为了让读者知道这个函数的存在,在有些时候需要使用这个函数来查找一些没有使用特定Tag的对象。
- 除了删除LevelTimer对象,OnDestroy()函数还会查找场景中所有的焰火对象,并启动这些对象。OnDestroy()函数中调用了GameObject.FindGameObjectsWithTag()函数来查找所有具有匹配Tag的对象。GameObject.FindGameObjectsWithTag()函数会返回所有具有“Firework”标签的对象,并通过调用Play函数启动烟火系统中的每一个对象。
注意
如前所述,Unity中的每一个对象都是一些相关组件的集合。例如,一个标准立方体(使用菜单GameObject | 3D Object | Cube所创建的),就是由Transform组件、Mesh Filter组件、Mesh Renderer组件以及Box Collider组件所组成的。这些组件共同决定了立方体的性质。
在脚本中使用函数GetComponent()可以获得一个目标组件的引用,这样就可以直接访问目标组件的公共属性。前面代码中的OnDestroy()函数就使用GetComponent()函数获得了“Particle System”组件的引用,这个函数是一个十分重要而且有用的函数,关于GetComponent()函数的更多详细信息,可以访问http://docs.Unity3d.com/ Script Reference/GameObject. GetComponent.html上的Unity在线文档。