呂學(xué)琴 蘇閏 陳彥軍
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游戲制作的目標(biāo)效果
塔防游戲的三大要素:敵人、炮塔、地圖。本文中制作的塔防游戲設(shè)置4波敵人,每波敵人具備不同的移速和血量,消滅難度遞增;設(shè)計3種炮塔,每種炮塔各有玄機(jī)并且可進(jìn)階為威力更強(qiáng)、射程更廣的升級版炮塔;地圖為15×15的網(wǎng)格形式,其中包括敵人起點(diǎn)、終點(diǎn)以及敵人行進(jìn)的道路。
玩家通過金幣購買炮塔并安置在地圖上,炮塔將自動攻擊敵人。敵人將一波一波地輪番出現(xiàn),每波敵人被完全消滅后才會出現(xiàn)下一波敵人。如果有一個敵人到達(dá)終點(diǎn),游戲?qū)⑿媸?。?dāng)玩家將4波敵人全都消滅時,則判定為勝利[1]。
2敵人
2.1敵人路徑管理
在敵人路徑上設(shè)置一些路徑點(diǎn)用于引導(dǎo)敵人移動:讓敵人達(dá)到固定的路徑點(diǎn),從而實(shí)現(xiàn)敵人朝著既定方向移動和轉(zhuǎn)彎。
2.2創(chuàng)建并控制敵人的移動
游戲中有若干類敵人,用不同的顏色區(qū)分。使用Sphere(球物體)充當(dāng)敵人。首先創(chuàng)建1類敵人,重命名為Enemy1,并將Enemy1放到Start位置(敵人生成處)。當(dāng)敵人和路徑點(diǎn)很接近時,就要朝著下一個路徑點(diǎn)移動,此處設(shè)置為:兩者相距0.2個單位時,朝著下一個路徑點(diǎn)移動。
2.3創(chuàng)建敵人孵化器管理敵人的生成
新增另外3類敵人,分別命名為Enemy2、Enemy3、Enemy4。每類敵人有不同的生命值、移速和生成的數(shù)量。敵人將會一波一波地出現(xiàn),在各波梯隊(duì)之間應(yīng)有間隔,例如第二波敵人應(yīng)該在第一波敵人全部死亡或到達(dá)終點(diǎn)后才會出現(xiàn)。
敵人生成采用協(xié)程[2]的方式實(shí)現(xiàn),定義函數(shù)代碼如下。
對waves數(shù)組進(jìn)行遍歷,生成每個wave(一波)中的敵人數(shù)目(wave.count)。為此使用for循環(huán),每層循環(huán)生成一個敵人。每個敵人生成完畢后,需要暫停極短時間,即第5行。每一波敵人生成完畢后再暫停若干秒時間,即第6行。
3炮塔
3.1創(chuàng)建3種炮臺的Prefab
游戲中,玩家可以選擇部署3種炮塔對敵人進(jìn)行攻擊。3種炮塔有自己的攻擊模式,且價格不同。
3.2創(chuàng)建炮塔選擇的UI
要實(shí)現(xiàn)玩家能夠在游戲中創(chuàng)建炮塔,需要有一個UI界面供玩家選擇炮臺。UI上有3個按鈕,代表3個炮塔。創(chuàng)建UI,選擇Toggle(單選按鈕),然后修改其中的屬性。將Toggle中的Is On取消勾選,這樣在最初開始就沒有炮臺被選中。此時,3個按鈕還不能做到單選。在Canves中創(chuàng)建空物體,重命名為TurretSwitch,并將所有的Toggle放在其下。為TurretSwitch添加Toggle Group組件,再將TurretSwitch掛載到每類Toggle上,這樣就實(shí)現(xiàn)了3個按鈕的單選[2]。
3.3監(jiān)聽炮塔選擇的事件
創(chuàng)建一個炮塔的管理類,用于保存當(dāng)前選擇的炮塔。
玩家通過點(diǎn)擊UI中的炮塔圖標(biāo)做出對炮塔的選擇,因此需要監(jiān)聽玩家選中了哪個炮塔。在每個Toggle中添加On Value Changed的事件。這樣就可以為每個Toggle注冊O(shè)n Value Changed的事件。在此基礎(chǔ)上,當(dāng)玩家點(diǎn)擊了一個炮塔圖標(biāo),就會讓該炮塔的Is On屬性變?yōu)門rue,其它2個炮塔的Is On屬性變?yōu)镕alse,此時值就發(fā)生了變化,事件被成功監(jiān)聽后就會調(diào)用相應(yīng)的函數(shù)。
3.4檢測鼠標(biāo)點(diǎn)擊到哪個MapCube
玩家選擇了炮塔后,就要將炮塔放置在Cube上,此時就要檢測玩家選定了哪個MapCube。這里采用射線檢測,即從鼠標(biāo)發(fā)出射線,查看射線碰撞到哪一個MapCube。
將MapCube設(shè)置為一層(Layer),這樣在射線檢測時,就可以指定檢測碰撞在MapCube層,而不與其它層進(jìn)行碰撞檢測。當(dāng)玩家操作轉(zhuǎn)為鼠標(biāo)點(diǎn)擊時,鼠標(biāo)如果在UI上,此后接續(xù)的就是炮塔的選擇。這時需要對鼠標(biāo)是否點(diǎn)擊到UI進(jìn)行判斷。 當(dāng)沒有在UI上時,就指定和Mapcube層進(jìn)行射線檢測。
3.5幣值不足的提示效果
當(dāng)金幣不足時,將不能建造炮塔,此時總金額閃爍,提示玩家金幣不足。為呈現(xiàn)這一效果,要為總金額的Label添加動畫。創(chuàng)建Animation文件夾,并創(chuàng)建子文件夾Money,用于保存總金額閃爍的動畫。為Money標(biāo)簽創(chuàng)建動畫,界面效果如圖1所示。
添加關(guān)鍵幀,改變相鄰關(guān)鍵幀的顏色,實(shí)現(xiàn)閃爍的效果。只有在金幣不足時,才會閃爍,且動畫只播放一次。這就需要編輯狀態(tài)機(jī),界面設(shè)計效果如圖2所示。創(chuàng)建一個新狀態(tài)(new state),重命名為Empty,并設(shè)為默認(rèn)狀態(tài),也就是沒有閃爍。Empty狀態(tài)可以轉(zhuǎn)變?yōu)镕liker狀態(tài),當(dāng)Flicker狀態(tài)結(jié)束(動畫播放了一次)轉(zhuǎn)回Empty狀態(tài)。將Flicker動畫的循環(huán)(Loop Time)選項(xiàng)取消。添加新的Trigger(觸發(fā)器)類型參數(shù),重命名為Flicker。接下來將Empty狀態(tài)切換到Flicker狀態(tài)的條件設(shè)置為Flicker,為此將特別取消Has Exit Time選項(xiàng)。Flicker狀態(tài)切換到Empty狀態(tài)則不變。
3.6利用粒子系統(tǒng)創(chuàng)建營造的特效
為了增加游戲的真實(shí)感,每當(dāng)建造炮塔時四周會揚(yáng)起泥土。這里使用Unity自帶的粒子效果來實(shí)現(xiàn)該特效,并在每次創(chuàng)建炮塔時實(shí)例化該特效。
首先創(chuàng)建一個空物體并重命名為BuildEffect,然后在其下添加Particle System(粒子系統(tǒng)),對粒子系統(tǒng)進(jìn)行修改,使之生成像素風(fēng)格的泥土。
參數(shù)設(shè)置如圖3所示。其中,Renderer用于控制粒子渲染模式,這里將其模式更改為Mesh,再為其添加材質(zhì),就能噴射出像素風(fēng)格的泥土。而后調(diào)整粒子的大小、生命周期、噴射速度等參數(shù),使其狀似濺射的泥土。
4炮塔攻擊敵人
4.1添加觸發(fā)器,檢測炮臺附近的敵人
為了讓炮塔能夠發(fā)現(xiàn)敵人。需要為炮塔添加碰撞器,當(dāng)敵人與碰撞器碰撞后,就提示炮塔發(fā)現(xiàn)敵人。先為標(biāo)準(zhǔn)型炮塔添加碰撞器。這里使用球形碰撞器,并設(shè)置為觸發(fā)器(將Is Trigger選項(xiàng)選上)。還要添加剛體(Rigidbody),并取消重力(不選Use Gravity)。
為標(biāo)準(zhǔn)型炮塔添加Turret腳本,用于識別并攻擊敵人??紤]到可能同時有多個敵人進(jìn)入攻擊范圍,就要創(chuàng)建一個列表用于存放進(jìn)入的敵人,這樣炮塔會優(yōu)先攻擊先進(jìn)入的敵人,直至敵人死亡后,再攻擊下一個。
4.2控制炮臺發(fā)射炮彈
炮塔在檢測到敵人后就要開啟攻擊了。定義變量attckRateTime表示每多少秒發(fā)射一次炮彈。另外還需要定義計時器,當(dāng)計時器timer預(yù)設(shè)時間到,后才能進(jìn)行一次攻擊。研發(fā)代碼可詳見如下。
計時器的累加在Update函數(shù)中完成。當(dāng)計時器累計時間達(dá)到攻擊閾值并且有敵人進(jìn)入射程就調(diào)用Attack函數(shù)進(jìn)行攻擊。攻擊時,timer也要重置為0。在炮塔創(chuàng)建之初就能對敵人進(jìn)行攻擊,所以在Start方法中,將timer初始化為attckRateTime。
在發(fā)起攻擊前需給出炮彈定義。在標(biāo)準(zhǔn)型炮塔的炮口下,創(chuàng)建一個空物體并重命名為FirePosition,用來定位炮彈的位置。如此一來,當(dāng)有敵人進(jìn)入炮塔射程,就會在炮口實(shí)例化一個炮彈。
4.3控制炮彈的飛行
5炮塔升級
5.1創(chuàng)建炮塔升級的UI按鈕
當(dāng)鼠標(biāo)點(diǎn)擊到已經(jīng)創(chuàng)建的炮塔時,可以選擇讓炮塔升級或是拆毀已有的炮塔。這個UI可以被所有的炮塔所共用(包括升級后的炮塔)。當(dāng)點(diǎn)擊一個炮塔后,在炮塔上方出現(xiàn)UI,其它處的UI消失,同一時刻至多有一座炮塔上方有UI。創(chuàng)建Canvas,重命名為UpgradeCancas,并添加2個按鈕。一個為升級,另一個為拆毀。調(diào)整按鈕和畫布的相對位置和大小。將畫布的中心點(diǎn)放在Cube中心點(diǎn)處,并且使2個按鈕置于炮塔上方[3]。
此后,就是給按鈕添加動畫,控制升級面板顯示和隱藏方法的創(chuàng)建,用于控制升級面板的顯示和隱藏。
5.2處理升級按鈕和拆按鈕的點(diǎn)擊事件
升級炮塔時要明確被升級炮塔的類型。在BuildManager腳本持有的是已選中的炮塔(變量selectedTurretGo),但是升級功能是在MapCube腳本中運(yùn)行通過的,也就是需要保存當(dāng)前選中的MapCube,調(diào)用MapCube腳本中的UpgradeTurret函數(shù)完成升級。研究中,可參考如下設(shè)計代碼。
5.3創(chuàng)建剩余類型的炮臺及其升級的預(yù)制體
為標(biāo)準(zhǔn)炮塔的升級預(yù)制體添加腳本,并掛載相應(yīng)的成分。為標(biāo)準(zhǔn)炮塔升級預(yù)制體同樣添加上球型碰撞器和剛體,設(shè)置半徑(比標(biāo)準(zhǔn)炮塔射程大),取消勾選使用重力。這樣標(biāo)準(zhǔn)炮塔升級預(yù)制體也可以進(jìn)行瞄準(zhǔn)攻擊了。
除此之外,還將涉及激光炮塔的設(shè)計研發(fā)。激光炮塔的球型碰撞器,剛體組件同樣可以從標(biāo)準(zhǔn)型炮塔上完整拷貝。為激光炮塔添加Turret腳本。激光炮塔無需子彈進(jìn)行攻擊,但激光有起始位置,并且炮塔頭部需要跟隨敵人進(jìn)行旋轉(zhuǎn)。
5.4利用LineRenderer顯示激光
為激光炮塔制作激光,這里使用的是LineRenderer組件。在設(shè)計上可以實(shí)現(xiàn)畫線的功能。在激光炮塔下添加空物體,重命名為Laser,為其添加LineRenderer組件。再為該組件添加材質(zhì),并調(diào)整寬度。使得描繪后畫出的線像一束光。
此時激光炮塔已經(jīng)可以瞄準(zhǔn)敵人并發(fā)出射線,但是一旦敵人離開射程,那條射線依然還在。為此,當(dāng)沒有敵人在射程內(nèi)時,不再使用LineRenderer組件。基于此,可得研發(fā)代碼如下。
將特效的位置設(shè)置在敵人的位置(第2行),并且特效需要朝向炮塔(第5行),當(dāng)時炮塔的中心是位于炮塔的下方,因而需要修改特效的縱向朝向,在豎直方向特效的朝向保持不動(第3、4行)。如果不做修改,那么特效將會朝向炮塔下方。
6結(jié)束語
本款研發(fā)游戲中,主要的6個物體、8個腳本,以及相互之間的關(guān)系,可用圖形進(jìn)行展現(xiàn),即如圖4所示。方框中的是物體,橢圓中的是腳本。各個腳本之間又存在著調(diào)用關(guān)系,箭頭上標(biāo)記了調(diào)用其它腳本的對象或函數(shù),箭頭起點(diǎn)是調(diào)用方,終點(diǎn)是被調(diào)用方[3]。本款游戲的成功實(shí)現(xiàn)也將為此后的同類研究提供有益的技術(shù)參考借鑒。
參考文獻(xiàn)
[1] 宣雨松. Unity3D游戲開發(fā)[M]. 北京:人民郵電出版社,2012.
[2] 商宇浩,李一帆,張吉祥. Unity 5.x 完全自學(xué)手冊[M]. 北京:電子工業(yè)出版社,2016.
[3] 李在賢. Unity 5權(quán)威講解[M]. 孔雪玲,譯. 北京:人民郵電出版社,2016.
[4] Unity Technologies. Unity 5.x 從入門到精通[M]. 北京:中國鐵道出版社,2016.
[5] SKEET J. 深入理解C# [M]. 3版. 姚琪琳,譯. 北京:人民郵電出版社,2014.
[6] JACKSON S. Unity UI設(shè)計[M]. 張騫,譯. 北京:清華大學(xué)出版社,2017.
[6] 李昆侖, 曹錚, 曹麗蘋, 等. 半監(jiān)督聚類的若干新進(jìn)展[J]. 模式識別與人工智能, 2009, 22(5): 735-742.
[7]王娜,李霞. 基于監(jiān)督信息特性的主動半監(jiān)督譜聚類算法[J]. 電子學(xué)報,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] 張惟皎, 劉春煌, 李芳玉. 聚類質(zhì)量的評價方法[J]. 計算機(jī)工程, 2005, 31(20): 10-12.
[10]楊燕, 靳蕃, MOHAMED K. 聚類有效性評價綜述[J].計算機(jī)應(yīng)用研究, 2008,25(6):1630-1632,1638.