基于Unity引擎制作塔防游戏

2018-10-20 11:01吕学琴苏闰陈彦军
智能计算机与应用 2018年5期
关键词:炮塔脚本激光

吕学琴 苏闰 陈彦军

Abstract: The tower defense game allows players to fully use their imaginations in the game, build different kinds of turrets according to the terrain, and use them to make multiple rounds of confrontation with enemies that are constantly emerging. The Unity game engine, which is also popular in the world of game production in recent years, is a comprehensive game development tool that allows players to easily create types such as 3D games and 3D animations. This paper is based on the Unity engine to make a tower defense game.

1游戏制作的目标效果

塔防游戏的三大要素:敌人、炮塔、地图。本文中制作的塔防游戏设置4波敌人,每波敌人具备不同的移速和血量,消灭难度递增;设计3种炮塔,每种炮塔各有玄机并且可进阶为威力更强、射程更广的升级版炮塔;地图为15×15的网格形式,其中包括敌人起点、终点以及敌人行进的道路。

玩家通过金币购买炮塔并安置在地图上,炮塔将自动攻击敌人。敌人将一波一波地轮番出现,每波敌人被完全消灭后才会出现下一波敌人。如果有一个敌人到达终点,游戏将宣告失败。当玩家将4波敌人全都消灭时,则判定为胜利[1]。

2敌人

2.1敌人路径管理

在敌人路径上设置一些路径点用于引导敌人移动:让敌人达到固定的路径点,从而实现敌人朝着既定方向移动和转弯。

2.2创建并控制敌人的移动

游戏中有若干类敌人,用不同的颜色区分。使用Sphere(球物体)充当敌人。首先创建1类敌人,重命名为Enemy1,并将Enemy1放到Start位置(敌人生成处)。当敌人和路径点很接近时,就要朝着下一个路径点移动,此处设置为:两者相距0.2个单位时,朝着下一个路径点移动。

2.3创建敌人孵化器管理敌人的生成

新增另外3类敌人,分别命名为Enemy2、Enemy3、Enemy4。每类敌人有不同的生命值、移速和生成的数量。敌人将会一波一波地出现,在各波梯队之间应有间隔,例如第二波敌人应该在第一波敌人全部死亡或到达终点后才会出现。

敌人生成采用协程[2]的方式实现,定义函数代码如下。

对waves数组进行遍历,生成每个wave(一波)中的敌人数目(wave.count)。为此使用for循环,每层循环生成一个敌人。每个敌人生成完毕后,需要暂停极短时间,即第5行。每一波敌人生成完毕后再暂停若干秒时间,即第6行。

3炮塔

3.1创建3种炮台的Prefab

游戏中,玩家可以选择部署3种炮塔对敌人进行攻击。3种炮塔有自己的攻击模式,且价格不同。

3.2创建炮塔选择的UI

要实现玩家能够在游戏中创建炮塔,需要有一个UI界面供玩家选择炮台。UI上有3个按钮,代表3个炮塔。创建UI,选择Toggle(单选按钮),然后修改其中的属性。将Toggle中的Is On取消勾选,这样在最初开始就没有炮台被选中。此时,3个按钮还不能做到单选。在Canves中创建空物体,重命名为TurretSwitch,并将所有的Toggle放在其下。为TurretSwitch添加Toggle Group组件,再将TurretSwitch挂载到每类Toggle上,这样就实现了3个按钮的单选[2]。

3.3监听炮塔选择的事件

创建一个炮塔的管理类,用于保存当前选择的炮塔。

玩家通过点击UI中的炮塔图标做出对炮塔的选择,因此需要监听玩家选中了哪个炮塔。在每个Toggle中添加On Value Changed的事件。这样就可以为每个Toggle注册On Value Changed的事件。在此基础上,当玩家点击了一个炮塔图标,就会让该炮塔的Is On属性变为True,其它2个炮塔的Is On属性变为False,此时值就发生了变化,事件被成功监听后就会调用相应的函数。

3.4检测鼠标点击到哪个MapCube

玩家选择了炮塔后,就要将炮塔放置在Cube上,此时就要检测玩家选定了哪个MapCube。这里采用射线检测,即从鼠标发出射线,查看射线碰撞到哪一个MapCube。

将MapCube设置为一层(Layer),这样在射线检测時,就可以指定检测碰撞在MapCube层,而不与其它层进行碰撞检测。当玩家操作转为鼠标点击时,鼠标如果在UI上,此后接续的就是炮塔的选择。这时需要对鼠标是否点击到UI进行判断。 当没有在UI上时,就指定和Mapcube层进行射线检测。

3.5币值不足的提示效果

当金币不足时,将不能建造炮塔,此时总金额闪烁,提示玩家金币不足。为呈现这一效果,要为总金额的Label添加动画。创建Animation文件夹,并创建子文件夹Money,用于保存总金额闪烁的动画。为Money标签创建动画,界面效果如图1所示。

添加关键帧,改变相邻关键帧的颜色,实现闪烁的效果。只有在金币不足时,才会闪烁,且动画只播放一次。这就需要编辑状态机,界面设计效果如图2所示。创建一个新状态(new state),重命名为Empty,并设为默认状态,也就是没有闪烁。Empty状态可以转变为Fliker状态,当Flicker状态结束(动画播放了一次)转回Empty状态。将Flicker动画的循环(Loop Time)选项取消。添加新的Trigger(触发器)类型参数,重命名为Flicker。接下来将Empty状态切换到Flicker状态的条件设置为Flicker,为此将特别取消Has Exit Time选项。Flicker状态切换到Empty状态则不变。

3.6利用粒子系统创建营造的特效

为了增加游戏的真实感,每当建造炮塔时四周会扬起泥土。这里使用Unity自带的粒子效果来实现该特效,并在每次创建炮塔时实例化该特效。

首先创建一个空物体并重命名为BuildEffect,然后在其下添加Particle System(粒子系统),对粒子系统进行修改,使之生成像素风格的泥土。

参数设置如图3所示。其中,Renderer用于控制粒子渲染模式,这里将其模式更改为Mesh,再为其添加材质,就能喷射出像素风格的泥土。而后调整粒子的大小、生命周期、喷射速度等参数,使其状似溅射的泥土。

4炮塔攻击敌人

4.1添加触发器,检测炮台附近的敌人

为了让炮塔能够发现敌人。需要为炮塔添加碰撞器,当敌人与碰撞器碰撞后,就提示炮塔发现敌人。先为标准型炮塔添加碰撞器。这里使用球形碰撞器,并设置为触发器(将Is Trigger选项选上)。还要添加刚体(Rigidbody),并取消重力(不选Use Gravity)。

为标准型炮塔添加Turret脚本,用于识别并攻击敌人。考虑到可能同时有多个敌人进入攻击范围,就要创建一个列表用于存放进入的敌人,这样炮塔会优先攻击先进入的敌人,直至敌人死亡后,再攻击下一个。

4.2控制炮台发射炮弹

炮塔在检测到敌人后就要开启攻击了。定义变量attckRateTime表示每多少秒发射一次炮弹。另外还需要定义计时器,当计时器timer预设时间到,后才能进行一次攻击。研发代码可详见如下。

计时器的累加在Update函数中完成。当计时器累计时间达到攻击阈值并且有敌人进入射程就调用Attack函数进行攻击。攻击时,timer也要重置为0。在炮塔创建之初就能对敌人进行攻击,所以在Start方法中,将timer初始化为attckRateTime。

在发起攻击前需给出炮弹定义。在标准型炮塔的炮口下,创建一个空物体并重命名为FirePosition,用来定位炮弹的位置。如此一来,当有敌人进入炮塔射程,就会在炮口实例化一个炮弹。

4.3控制炮弹的飞行

5炮塔升级

5.1创建炮塔升级的UI按钮

当鼠标点击到已经创建的炮塔时,可以选择让炮塔升级或是拆毁已有的炮塔。这个UI可以被所有的炮塔所共用(包括升级后的炮塔)。当点击一个炮塔后,在炮塔上方出现UI,其它处的UI消失,同一时刻至多有一座炮塔上方有UI。创建Canvas,重命名为UpgradeCancas,并添加2个按钮。一个为升级,另一个为拆毁。调整按钮和画布的相对位置和大小。将画布的中心点放在Cube中心点处,并且使2个按钮置于炮塔上方[3]。

此后,就是给按钮添加动画,控制升级面板显示和隐藏方法的创建,用于控制升级面板的显示和隐藏。

5.2处理升级按钮和拆按钮的点击事件

升级炮塔时要明确被升级炮塔的类型。在BuildManager脚本持有的是已选中的炮塔(变量selectedTurretGo),但是升级功能是在MapCube脚本中运行通过的,也就是需要保存当前选中的MapCube,调用MapCube脚本中的UpgradeTurret函数完成升级。研究中,可参考如下设计代码。

5.3创建剩余类型的炮台及其升级的预制体

为标准炮塔的升级预制体添加脚本,并挂载相应的成分。为标准炮塔升级预制体同样添加上球型碰撞器和刚体,设置半径(比标准炮塔射程大),取消勾选使用重力。这样标准炮塔升级预制体也可以进行瞄准攻击了。

除此之外,还将涉及激光炮塔的设计研发。激光炮塔的球型碰撞器,刚体组件同样可以从标准型炮塔上完整拷贝。为激光炮塔添加Turret脚本。激光炮塔无需子弹进行攻击,但激光有起始位置,并且炮塔头部需要跟随敌人进行旋转。

5.4利用LineRenderer显示激光

为激光炮塔制作激光,这里使用的是LineRenderer组件。在设计上可以实现画线的功能。在激光炮塔下添加空物体,重命名为Laser,为其添加LineRenderer组件。再为该组件添加材质,并调整宽度。使得描绘后画出的线像一束光。

此时激光炮塔已经可以瞄准敌人并发出射线,但是一旦敌人离开射程,那条射线依然还在。为此,当没有敌人在射程内时,不再使用LineRenderer组件。基于此,可得研发代码如下。

將特效的位置设置在敌人的位置(第2行),并且特效需要朝向炮塔(第5行),当时炮塔的中心是位于炮塔的下方,因而需要修改特效的纵向朝向,在竖直方向特效的朝向保持不动(第3、4行)。如果不做修改,那么特效将会朝向炮塔下方。

6结束语

本款研发游戏中,主要的6个物体、8个脚本,以及相互之间的关系,可用图形进行展现,即如图4所示。方框中的是物体,椭圆中的是脚本。各个脚本之间又存在着调用关系,箭头上标记了调用其它脚本的对象或函数,箭头起点是调用方,终点是被调用方[3]。本款游戏的成功实现也将为此后的同类研究提供有益的技术参考借鉴。

参考文献

[1] 宣雨松. Unity3D游戏开发[M]. 北京:人民邮电出版社,2012.

[2] 商宇浩,李一帆,张吉祥. Unity 5.x 完全自学手册[M]. 北京:电子工业出版社,2016.

[3] 李在贤. Unity 5权威讲解[M]. 孔雪玲,译. 北京:人民邮电出版社,2016.

[4] Unity Technologies. Unity 5.x 从入门到精通[M]. 北京:中国铁道出版社,2016.

[5] SKEET J. 深入理解C# [M]. 3版. 姚琪琳,译. 北京:人民邮电出版社,2014.

[6] JACKSON S. Unity UI设计[M]. 张骞,译. 北京:清华大学出版社,2017.

[6] 李昆仑, 曹铮, 曹丽苹, 等. 半监督聚类的若干新进展[J]. 模式识别与人工智能, 2009, 22(5): 735-742.

[7]王娜,李霞. 基于监督信息特性的主动半监督谱聚类算法[J]. 电子学报,2010,38(1):172-176.

[8] BASU S, BANERJEE A, MOONEY R J. Semi-supervised clustering by seeding[C]//Proceeding of 19th International Conference on Machine Learning(ICML-2002). San Francisco, CA, USA: Morgan Kaufmann Publishers Inc, 2002:27-34.

[9] 张惟皎, 刘春煌, 李芳玉. 聚类质量的评价方法[J]. 计算机工程, 2005, 31(20): 10-12.

[10]杨燕, 靳蕃, MOHAMED K. 聚类有效性评价综述[J].计算机应用研究, 2008,25(6):1630-1632,1638.

猜你喜欢
炮塔脚本激光
坦克炮塔为何容易被炸飞
阅读理解专练
自动推送与网站匹配的脚本
莱茵金属公司将扩展德国“美洲狮”步兵战车性能
伊朗新型“克拉尔”KARRAR主战坦克在当地电视台出现
激光3D长绳
神奇的激光
举一反三新编
捕风捉影新编
骑着激光炸敌人