Unity官方实例教程 Space Shooter(三)

传送门
Unity官方实例教程 Space Shooter(一)
Unity官方实例教程 Space Shooter(二)
Unity官方实例教程 Space Shooter(三)
Unity官方实例教程 Space Shooter(四)
Unity官方实例教程 Space Shooter(五)
前言

在Unity官方实例教程 Space Shooter(二)中,我们学会了:
- 如何控制飞船移动
- 如何添加游戏背景
- 如何制作子弹
- 如何控制飞船发射子弹
学会这些后,我们这个游戏慢慢的有点样子了,但是如果我们空有屠龙之术,却没有敌人给我们来做活靶,也就浪费我们之前做的努力的,所以我们这一节给玩家添加一些障碍吧
你将学到什么?
- 如何回收子弹
- 如何创建障碍物
- 如何实现子弹击碎障碍的效果
- 如何实现飞船撞击障碍的华丽爆炸效果
一、回收子弹
在上一节中,我们可以让飞船发射子弹了,但是却遗留下了一个问题,如果细心的朋友,可能会发现,当我们发射了许多子弹后,在Hierarchy窗口,出现了许多Bolt对象

因为在我们现在的游戏功能中,飞船每发射一颗子弹,就会生成一个Bolt对象,但是这个对象会一直存在,所以就会出现Bolt越来越多的情况,而这样就到导致一个问题,我们游戏内存吃紧,导致游戏越来越卡,所以我们比较做一点什么——回收子弹
大家想一下我们要回收子弹,那么我们应该在什么时候回收子弹呢?子弹一发出来我们就回收,这样就会达不到敌人了,毫无作用的子弹,比较合理的方式是,在子弹飞出我们的屏幕后,就将他回收掉,那么问题来了,怎么知道子弹已经飞出屏幕了呢?我们可以创建一个盒子,这个盒子大小和我们的屏幕差不多,然后我们可以判断如何子弹飞出了这个盒子,就意味着子弹飞出了屏幕,这个时候我们就可以通知程序来回收子弹了
所以,我们第一步,创建一个Cube,然后进行两个标准动作,并命名为Boundary,如下图:

然后我们将盒子拉扯到屏幕大小,在这里大家可以选择自己切换到Game视窗来调整盒子大小,也可以直接选中Boundary将其的Position Z设置为5,然后将其的Scale X和Z分别设置为14和20,然后你就发现这个盒子充满了整个屏幕

看到这里,你可能会说Oh My God!这游戏还能玩?没错,这样的游戏哪能玩呢?所以我们不能让盒子挡住了我们的背景,我们的飞船等一切的游戏内容,所以我们来看看盒子的Inspector窗口,看看有什么我们来尝试做一做的:

我们看到一个Mesh Renderer的组件,然后我们尝试他的勾选去掉,你就会惊奇的发现,所有的游戏内容都出来了,盒子不见了,我们切换到Scene窗口来看看到底发生了什么:

从上图我们可以看到,盒子的渲染不见了,只剩下绿色线框标记盒子的碰撞,这正是我们想要的效果,所以我们将盒子的Mesh Renderer组件直接删除掉,因为我们只需要用到他的碰撞,然后我给盒子添加一个新脚本,命名为DestroyByBoundary,然后我们打开脚本,输入以下代码:

- 我们在这个脚本中,只做了一件事情,就是检测有子弹飞出这个盒子后,我们就将子弹销毁掉
- OnTriggerExit是Unity内置方法,用来检测对象退出碰撞体时的操作
- Destroy作用是销毁一个对象
写完代码后,我们保存一下,然后回到Unity编辑器,运行一下游戏,这时候我再不停的发射子弹,就可以看到hierarchy视窗中Bolt对象不一会就会自己消失了,这就代表子弹被我们回收掉了。

二、创建障碍
创建障碍的方式和创建子弹很相似,同样的,为了方便制作,我们将障碍的逻辑和显示效果分开,首先我们创建一个空的GameObject,命名为Asteroid,然后为了方便测试我们将其的Position Z设置为8(做这个操作之前要记得先进行两个标准动作哦!)

然后我们给Asteroid添加美术效果,我们在Assets->Models文件夹中找到prop_asteroid_01文件,然后将其拖入Asteroid做其的子对象

然后我们要将prop_asteroid_01的Transform进行重置,这样我们的美术效果就做好了

接下来我们要为Asteroid的添加刚体组件,并去掉Use Gravity属性

然后我们还需要为Asteroid添加胶囊碰撞体,并将碰撞大小调整为合适的大小
这里有个便捷操作,我们在调整碰撞的大小时,可以打开碰撞器的Edit Collider选项,这样就可以方便的调整碰撞器的大小了
Edit Collider选项

做完这些后,我们的可以运行一下游戏,
…………
…………
你会发现太无聊了,这个障碍一动不动的,所以接下来我们给他增加一些变化。选中Asteroid,然后给他新建一个脚本,命名为RandomRotator,然后添加以下代码:

- 首先我们定义一个公共变量tumble来设置障碍翻滚的幅度
- 然后我们在Start函数中,通过随机数来随机设置障碍翻滚的速率
写完代码,保存一下,然后回到Unity编辑器,将tumble的值设为5,然后再运行游戏,我们便可以看到障碍旋转起来了

并且我们每次运行,障碍翻滚的角度都会不一样,但是如果我们运行时间久一点,就会发现障碍翻滚慢慢的停了下来,这是为什么呢?这是由于Rigidbody中的阻力导致的,所以为了让障碍的翻滚不会停下来,所以我们将阻力都设置为0

三、实现子弹击碎障碍
为了实现子弹击碎障碍的功能,我再为障碍新增一个脚本,命名为DestroyByContact,然后我们想一下要实现子弹击碎障碍的功能,我们要做一些什么?
- 首先我们需要检测子弹和障碍是否碰撞
- 然后如果碰撞了,我们需要创建一个爆炸效果来给予反馈
- 最后我们还需要将子弹和障碍删除掉
我们来看看如何用代码实现上面的事情:

- 首先我们定义了一个公共变量,用来设置爆炸的效果
- 然后我们利用OnTriggerEnter方法来检测障碍是否和子弹碰撞
- 如果碰撞了,我们就利用Instantiate方法生成一个爆炸效果
- 然后我删除子弹
- 最后我们将障碍也删除
写完代码,保存一下,然后回到Unity编辑器,接着在Assets->Prefabs->VFX->Explosions文件夹中找到explosion_asteroid文件,然后拖入到我们定义的explosion变量中

做完这些我们便可以运行游戏,看看效果

额,怎么游戏一开始,还没发射子弹,障碍就爆炸了呢?这是为什么呢?我们回到Scene视窗来看看到底是什么原因导致

从上面我们可以看到,之前为什么回收子弹,我们创建了一个大盒子,所以游戏一开始,就检测到障碍和盒子的碰撞,所以障碍一开始就爆炸了,为了避免这种情况,我们需要让障碍变得聪明一点,让它能够区分只有和子弹进行碰撞才会发生爆炸,我们回到DestroyByContact脚本,新增以下代码:

- 我们在碰撞中,增加一个判断,如果碰撞物的tag(标志)是Boundary,我们就什么都不做,直接retrun
写完代码,保存一下,然后回到Unity编辑器,再给我的盒子(Boundary)添加一个新的Tag,命名为Boundary,关于如何添加Tag请参见Unity官方实例教程 Roll-a-Ball(二)的相关内容
做完这些,我们再次运行一下,就发现一切正常了

做到这里,或许有细心的朋友会发现,除了子弹碰撞障碍会爆炸外,我们的飞船碰到障碍也会爆炸,但是爆炸的效果都是一样的,这样有点太无聊了,所以我们让飞船碰到障碍来个不一样的爆炸效果。我们继续打开DestroyByContact脚本,新增以下代码:

- 首先我们定一个公共变量playerExplosion,来设置飞船爆炸的效果
- 接着我们在碰撞里面进行判断,如果碰撞对象的Tag为Player,也就是我们的飞船,我们就在飞船的位置播放一个爆炸效果
写完代码,保存一下,然后回到Unity编辑器,将Player也就是我们的飞船的Tag设置为Player,然后在Assets->Prefabs->VFX->Explosions文件夹中找到explosion_player文件,拖入到变量playerExplosion中

做完这些,然后运行游戏测试一下,就会发现飞船碰到障碍会出现一个更加华丽的爆炸

可能有些朋友会出现飞船撞击障碍没有效果的问题,可以试着检查一下是否是关闭了Mesh Collider组件
关闭了**Mesh Collider**组件
下集预告
在下一集,我们将学会:
- 如何随机生成一个障碍
- 如何生成多个障碍
- 如何设置障碍生成的间隔
- 如何生成无尽波数的障碍