传送门
Unity官方实例教程 Space Shooter(一)
Unity官方实例教程 Space Shooter(二)
Unity官方实例教程 Space Shooter(三)
Unity官方实例教程 Space Shooter(四)
Unity官方实例教程 Space Shooter(五)
前言
在Unity官方实例教程 Space Shooter(三)中,我们学会了:
- 如何回收子弹
- 如何创建障碍物
- 如何实现子弹击碎障碍的效果
- 如何实现飞船撞击障碍的华丽爆炸效果
现在我们的游戏已经具备了基本的玩法了,但是我们的障碍还是太少了,玩家击碎一个之后,就已经无所事事了,所以我们需要加大难度,来看看我们这一节会做哪些事情。
你将学到什么?
- 如何让障碍向下移动对玩家造成威胁
- 如何随机生成一个障碍
- 如何生成多个障碍
- 如何设置障碍生成的间隔
- 如何生成无尽波数的障碍
- 如何基于时间来回收GameObject
一、实现障碍向下移动
我们让障碍能够往下移动,这样才能对我们的飞船造成一些威胁。不知道大家是否还记得当初我们让子弹向前飞行的做法,有了这个东西,我们就能很快的让障碍向下移动,首先我们给障碍添加之前我们创建过的Mover脚本,然后将speed变量设置为-5,运行一下游戏,看看障碍是不是向下移动了
很好,我们看到障碍已经向下移动了,飞船如果不躲避,也会被他撞毁,下面我们就要来生成更多的障碍了,首先我们来思考一下,要实现生成更多的障碍,我们应该做什么?
- 首先我们需要能够自动生成一个障碍物
- 而且这个障碍能够随机出现在不同的位置,不然就太没有挑战了
我们先来看看如何随机生成一个障碍
二、随机生成障碍
首先,我们这些逻辑需要绑定在一个游戏控制器上,所以我们新建一个空的GameObject,命名为GameController,然后给GameController添加一个新的脚本,也命名为GameController(有点绕,希望大家耐心点),然后我们打开GameController脚本输入以下代码:
- 首先我们定义一个公共变量hazard,来设置生成的障碍对象
- 然后我们继续定义一个公共变量spawnValue,它是一个Vector3的变量,用来设置障碍生成的位置,我们可以在编辑器中设置
- 接着我们在Start方法中调用SpawnWaves方法,因为很多我们自定义的方法,Unity都不会自动调用的,需要我们自己在合适的地方去调用
- 然后我们定义了SpawnWaves方法,我们来看看这个方法里面做了什么?
- 首先我们在方法里面定义了一个局部变量spawnPosition,这个变量是用来记录障碍生成的位置,我们来看看如何对他进行赋值
- 我们通过new Vector3的方法来新建了一个Vector3,而它的xyz值,我们对它进行了分别的设置,x值是在我们设置的spawnValue的x的[-x, x]之间随机,这样才能保证我们的障碍每次生成在不同的位置上
- y和z我们直接调用spawnValue的y和z值,而spawnValue的y和z值是后面我们在编辑器里面进行设置,来确保障碍生成的位置在屏幕的上方
- 障碍的Position属性搞定后,我们要看看它的Rotation属性如何确定,Rotation属性是一个Quaternion类型的变量,所以我们定义了一个spawnRotation的变量,用来记录障碍的Rotation属性,在这里我们不需要让障碍一开始带着任何的旋转,所以我们直接赋值Quaternion.identity
- 到现在,我们确定了障碍的对象hazard,障碍的Position,障碍的Rotation,我们便可以使用Instantiate方法生成一个障碍实例了
写完代码,保存一下,回到Unity编辑器,我们还需要做两件事情:
- 设置hazard
- 设置spawnValue
首先我们来看看如何设置hazard,hazard我们需要的其实就是我们的障碍物,但是现在障碍物还只是我们场景中的一个GameObject,为了方便使用,我们需要将它做成一个Prefab,我们首先进入到Assets->Prefabs文件下面,然后将Asteroid拖入到文件夹下面,这样我们的Prefab就做好了
然后我们在选中GameController,将Asteroid的Prefab拖入到hazard中
这样hazard我们就设置好了,下面我们来看看如何设置spawnValue,首先我们得知道spawnValue是用来确定障碍生成的位置的,由于我们游戏是顶视图,所以y值我们不会变化,直接设置为0,然后z值代表障碍在屏幕中的垂直位置,我们肯定希望障碍一开始从屏幕最上方掉下来,所以我们通过测量得知z值可以设置为16,而最后的x值代表障碍在屏幕中的水平位置,同时我们在代码中通过随机函数来确保障碍的x值在一定范围内随机,所以这个范围就是我们屏幕边界,通过测量,我们得到x的值为6,做好这些设置后,我们便可运行游戏来进行测试了,如无意外,我们每次运行游戏,障碍生成的位置都是随机的
三、让障碍来得更猛烈一些
现在我们可以随机生成障碍了,但是生成的障碍还是只有1个,这样太没有挑战性了,所以下面我们让障碍每次生成的数量变得多一点,那怎么让障碍生成数量边多一点了,聪明的朋友可能想到了,我们可以多调用几次生成障碍的方法就可以了,比如像下面这样:
我们运行一下游戏,发现这样确实能够起到效果,现在可以一次生成3个障碍了,但是这样的写法可不好,如果我们需要生成100个障碍呢?难道我们要写100句SpawnWaves?这显然是很笨的方法,所以我们在这里要用到循环函数来生成多个障碍
- 首先我们定义了一个公共变量hazardCount,用来设置每次生成的障碍的数量
- 然后我们修改了SpawnWaves方法,将生成的代码放入了一个for循环里面,循环的次数就是我们的hazardCount
写完代码,保存一下,然后回到Unity编辑器,将hazardCount的数量设置为10,再运行游戏测试一下,便可以看到一次生成了10个障碍
现在的确一次可以生成多个障碍了,但是还是存在几个问题:
- 障碍不是一个接一个的出现的
- 同时出现的障碍还会互相碰撞发生爆炸
所以我们需要让障碍间隔生成
四、如何设置障碍生成的间隔
要让障碍物一个个的生成,其实逻辑说起来很简单,就是让一障碍生成后,稍等一会,再生成第二个,依次类推,那我们来看看如何在代码里面实现这个功能
- 首先我们定义了一个公共变量spawnWait,用来设置每个障碍生成的间隔时间
- 然后我们又定义了一个公共变量startWait,用来设置游戏开始生成障碍的准备时间,我们给予玩家一定准备时间
- 然后我们来看这里里面最重要的一个语句yield return new WaitForSeconds,这给方法就是让代码等待一定时间,这是个协同程序,可以让游戏不暂停的同时,让代码暂停(关于协同程序这里大家不用太在意他的内容,只要理解我们这里通过这个代码来实现让代码等待一定时间的效果就好了)
- 然后我们看一下,我们在方法最开始,使用yield return new WaitForSeconds语句,让代码等待startWait秒,然后再开始执行下面的代码,这样就实现了游戏开始给予玩家准备时间的功能
- 接着我们在每一次循环结束后,使用yield return new WaitForSeconds语句,让代码等待spawnWait秒,然后再开始执行下一次循环,这样就实现了障碍生存间隔的效果
- 然后为了使用yield return new WaitForSeconds语句,我们还需要将SpawnWaves的返回值改为IEnumerator类型
- 最后调用SpawnWaves方法也需要修改为StartCoroutine (SpawnWaves ())
写完代码,保存一下,然后回到Unity编辑器,并且将startWait和spawnWait的时间都设置为1,运行游戏测试一下
到这里看上去越来越棒了,但是还是有问题,障碍落下10个之后,就不会再落下来了,这可不太好玩,我们能不能让他一直落下呢?当然可以!
五、实现无限波数的障碍
要实现无限波数的障碍,我们需要用到一个新的循环语句——While循环,我们直接看代码来说明
- 首先我们定义一个公共变量waveWait,用来设置每一波的间隔时间
- 然后我们使用一个While循环,这里我们将里面的判断条件直接写为true,让它可以一直循环,然后将我们生成障碍的代码放入While循环中
- 之后在每次循环结束是,我们使用yield return new WaitForSeconds语句,让代码等待waveWait秒
写完代码,保存一下,然后回到Unity编辑器,将waveWait的值设置为3,接着运行游戏测试一下,我们可以看到,现在障碍会不停的生成了
六、回收爆炸效果
也许有些细心的朋友已经发现了,我们在游戏中发生的爆炸效果,都会创建一个GameObject,随着玩家击碎障碍越多,爆炸效果的GameObject就会越多
这些效果越多,就会让游戏的负担越大,所以我们也需要及时的进行清理,那么怎么来清理呢?我们无法像清理子弹一样,如果子弹飞出屏幕就将他清楚,因为爆炸效果是不会移动的,既然这样,我们就只能通过时间来控制了,我们让每个爆炸效果存在一定时间后就会自动清楚,就像给它绑上了一个定时炸弹一样,时间一到就会爆炸,将其清楚掉,首先我们在Assets->Scripts文件夹下面新建一个名为DestroyByTime的脚本,然后输入以下代码:
- 首先我们定义一个公共变量lifeTime,来设置GameObject的存活时间,时间一到就会被销毁
- 然后我们在Start方法中,调用Destroy方法来消除GameObject,第二个参数就是我们的lifeTime
写完代码,保存一下,然后回到Unity编辑器,找到我们的爆炸效果的Prefab,然后添加DestroyByTime脚本
脚本添加完成后,我们再将lifeTime的值设置为2,运行游戏测试一下,这次我们发现所有的爆炸效果,再生成2秒后就会自己消除了
下集预告
在下一集中,我们将会学到:
- 如何给游戏添加背景音乐
- 如何给游戏添加各种音效
- 如何给飞船击碎障碍后进行计分
- 如何判断游戏结束
- 如何重新开始游戏
- 如何发布游戏