
傳送門
Unity官方實例教程 Space Shooter(一)
Unity官方實例教程 Space Shooter(二)
Unity官方實例教程 Space Shooter(三)
Unity官方實例教程 Space Shooter(四)
Unity官方實例教程 Space Shooter(五)
前言

在Unity官方實例教程 Space Shooter(三)中,我們學(xué)會了:
- 如何回收子彈
- 如何創(chuàng)建障礙物
- 如何實現(xiàn)子彈擊碎障礙的效果
- 如何實現(xiàn)飛船撞擊障礙的華麗爆炸效果
現(xiàn)在我們的游戲已經(jīng)具備了基本的玩法了,但是我們的障礙還是太少了,玩家擊碎一個之后,就已經(jīng)無所事事了,所以我們需要加大難度,來看看我們這一節(jié)會做哪些事情。
你將學(xué)到什么?
- 如何讓障礙向下移動對玩家造成威脅
- 如何隨機(jī)生成一個障礙
- 如何生成多個障礙
- 如何設(shè)置障礙生成的間隔
- 如何生成無盡波數(shù)的障礙
- 如何基于時間來回收GameObject
一、實現(xiàn)障礙向下移動
我們讓障礙能夠往下移動,這樣才能對我們的飛船造成一些威脅。不知道大家是否還記得當(dāng)初我們讓子彈向前飛行的做法,有了這個東西,我們就能很快的讓障礙向下移動,首先我們給障礙添加之前我們創(chuàng)建過的Mover腳本,然后將speed變量設(shè)置為-5,運(yùn)行一下游戲,看看障礙是不是向下移動了

很好,我們看到障礙已經(jīng)向下移動了,飛船如果不躲避,也會被他撞毀,下面我們就要來生成更多的障礙了,首先我們來思考一下,要實現(xiàn)生成更多的障礙,我們應(yīng)該做什么?
- 首先我們需要能夠自動生成一個障礙物
- 而且這個障礙能夠隨機(jī)出現(xiàn)在不同的位置,不然就太沒有挑戰(zhàn)了
我們先來看看如何隨機(jī)生成一個障礙
二、隨機(jī)生成障礙
首先,我們這些邏輯需要綁定在一個游戲控制器上,所以我們新建一個空的GameObject,命名為GameController,然后給GameController添加一個新的腳本,也命名為GameController(有點繞,希望大家耐心點),然后我們打開GameController腳本輸入以下代碼:

- 首先我們定義一個公共變量hazard,來設(shè)置生成的障礙對象
- 然后我們繼續(xù)定義一個公共變量spawnValue,它是一個Vector3的變量,用來設(shè)置障礙生成的位置,我們可以在編輯器中設(shè)置
- 接著我們在Start方法中調(diào)用SpawnWaves方法,因為很多我們自定義的方法,Unity都不會自動調(diào)用的,需要我們自己在合適的地方去調(diào)用
- 然后我們定義了SpawnWaves方法,我們來看看這個方法里面做了什么?
- 首先我們在方法里面定義了一個局部變量spawnPosition,這個變量是用來記錄障礙生成的位置,我們來看看如何對他進(jìn)行賦值
- 我們通過new Vector3的方法來新建了一個Vector3,而它的xyz值,我們對它進(jìn)行了分別的設(shè)置,x值是在我們設(shè)置的spawnValue的x的[-x, x]之間隨機(jī),這樣才能保證我們的障礙每次生成在不同的位置上
- y和z我們直接調(diào)用spawnValue的y和z值,而spawnValue的y和z值是后面我們在編輯器里面進(jìn)行設(shè)置,來確保障礙生成的位置在屏幕的上方
- 障礙的Position屬性搞定后,我們要看看它的Rotation屬性如何確定,Rotation屬性是一個Quaternion類型的變量,所以我們定義了一個spawnRotation的變量,用來記錄障礙的Rotation屬性,在這里我們不需要讓障礙一開始帶著任何的旋轉(zhuǎn),所以我們直接賦值Quaternion.identity
- 到現(xiàn)在,我們確定了障礙的對象hazard,障礙的Position,障礙的Rotation,我們便可以使用Instantiate方法生成一個障礙實例了
寫完代碼,保存一下,回到Unity編輯器,我們還需要做兩件事情:
- 設(shè)置hazard
- 設(shè)置spawnValue
首先我們來看看如何設(shè)置hazard,hazard我們需要的其實就是我們的障礙物,但是現(xiàn)在障礙物還只是我們場景中的一個GameObject,為了方便使用,我們需要將它做成一個Prefab,我們首先進(jìn)入到Assets->Prefabs文件下面,然后將Asteroid拖入到文件夾下面,這樣我們的Prefab就做好了

然后我們在選中GameController,將Asteroid的Prefab拖入到hazard中

這樣hazard我們就設(shè)置好了,下面我們來看看如何設(shè)置spawnValue,首先我們得知道spawnValue是用來確定障礙生成的位置的,由于我們游戲是頂視圖,所以y值我們不會變化,直接設(shè)置為0,然后z值代表障礙在屏幕中的垂直位置,我們肯定希望障礙一開始從屏幕最上方掉下來,所以我們通過測量得知z值可以設(shè)置為16,而最后的x值代表障礙在屏幕中的水平位置,同時我們在代碼中通過隨機(jī)函數(shù)來確保障礙的x值在一定范圍內(nèi)隨機(jī),所以這個范圍就是我們屏幕邊界,通過測量,我們得到x的值為6,做好這些設(shè)置后,我們便可運(yùn)行游戲來進(jìn)行測試了,如無意外,我們每次運(yùn)行游戲,障礙生成的位置都是隨機(jī)的
三、讓障礙來得更猛烈一些
現(xiàn)在我們可以隨機(jī)生成障礙了,但是生成的障礙還是只有1個,這樣太沒有挑戰(zhàn)性了,所以下面我們讓障礙每次生成的數(shù)量變得多一點,那怎么讓障礙生成數(shù)量邊多一點了,聰明的朋友可能想到了,我們可以多調(diào)用幾次生成障礙的方法就可以了,比如像下面這樣:

我們運(yùn)行一下游戲,發(fā)現(xiàn)這樣確實能夠起到效果,現(xiàn)在可以一次生成3個障礙了,但是這樣的寫法可不好,如果我們需要生成100個障礙呢?難道我們要寫100句SpawnWaves?這顯然是很笨的方法,所以我們在這里要用到循環(huán)函數(shù)來生成多個障礙

- 首先我們定義了一個公共變量hazardCount,用來設(shè)置每次生成的障礙的數(shù)量
- 然后我們修改了SpawnWaves方法,將生成的代碼放入了一個for循環(huán)里面,循環(huán)的次數(shù)就是我們的hazardCount
寫完代碼,保存一下,然后回到Unity編輯器,將hazardCount的數(shù)量設(shè)置為10,再運(yùn)行游戲測試一下,便可以看到一次生成了10個障礙

現(xiàn)在的確一次可以生成多個障礙了,但是還是存在幾個問題:
- 障礙不是一個接一個的出現(xiàn)的
- 同時出現(xiàn)的障礙還會互相碰撞發(fā)生爆炸
所以我們需要讓障礙間隔生成
四、如何設(shè)置障礙生成的間隔
要讓障礙物一個個的生成,其實邏輯說起來很簡單,就是讓一障礙生成后,稍等一會,再生成第二個,依次類推,那我們來看看如何在代碼里面實現(xiàn)這個功能

- 首先我們定義了一個公共變量spawnWait,用來設(shè)置每個障礙生成的間隔時間
- 然后我們又定義了一個公共變量startWait,用來設(shè)置游戲開始生成障礙的準(zhǔn)備時間,我們給予玩家一定準(zhǔn)備時間
- 然后我們來看這里里面最重要的一個語句yield return new WaitForSeconds,這給方法就是讓代碼等待一定時間,這是個協(xié)同程序,可以讓游戲不暫停的同時,讓代碼暫停(關(guān)于協(xié)同程序這里大家不用太在意他的內(nèi)容,只要理解我們這里通過這個代碼來實現(xiàn)讓代碼等待一定時間的效果就好了)
- 然后我們看一下,我們在方法最開始,使用yield return new WaitForSeconds語句,讓代碼等待startWait秒,然后再開始執(zhí)行下面的代碼,這樣就實現(xiàn)了游戲開始給予玩家準(zhǔn)備時間的功能
- 接著我們在每一次循環(huán)結(jié)束后,使用yield return new WaitForSeconds語句,讓代碼等待spawnWait秒,然后再開始執(zhí)行下一次循環(huán),這樣就實現(xiàn)了障礙生存間隔的效果
- 然后為了使用yield return new WaitForSeconds語句,我們還需要將SpawnWaves的返回值改為IEnumerator類型
- 最后調(diào)用SpawnWaves方法也需要修改為StartCoroutine (SpawnWaves ())
寫完代碼,保存一下,然后回到Unity編輯器,并且將startWait和spawnWait的時間都設(shè)置為1,運(yùn)行游戲測試一下

到這里看上去越來越棒了,但是還是有問題,障礙落下10個之后,就不會再落下來了,這可不太好玩,我們能不能讓他一直落下呢?當(dāng)然可以!
五、實現(xiàn)無限波數(shù)的障礙
要實現(xiàn)無限波數(shù)的障礙,我們需要用到一個新的循環(huán)語句——While循環(huán),我們直接看代碼來說明

- 首先我們定義一個公共變量waveWait,用來設(shè)置每一波的間隔時間
- 然后我們使用一個While循環(huán),這里我們將里面的判斷條件直接寫為true,讓它可以一直循環(huán),然后將我們生成障礙的代碼放入While循環(huán)中
- 之后在每次循環(huán)結(jié)束是,我們使用yield return new WaitForSeconds語句,讓代碼等待waveWait秒
寫完代碼,保存一下,然后回到Unity編輯器,將waveWait的值設(shè)置為3,接著運(yùn)行游戲測試一下,我們可以看到,現(xiàn)在障礙會不停的生成了
六、回收爆炸效果
也許有些細(xì)心的朋友已經(jīng)發(fā)現(xiàn)了,我們在游戲中發(fā)生的爆炸效果,都會創(chuàng)建一個GameObject,隨著玩家擊碎障礙越多,爆炸效果的GameObject就會越多

這些效果越多,就會讓游戲的負(fù)擔(dān)越大,所以我們也需要及時的進(jìn)行清理,那么怎么來清理呢?我們無法像清理子彈一樣,如果子彈飛出屏幕就將他清楚,因為爆炸效果是不會移動的,既然這樣,我們就只能通過時間來控制了,我們讓每個爆炸效果存在一定時間后就會自動清楚,就像給它綁上了一個定時炸彈一樣,時間一到就會爆炸,將其清楚掉,首先我們在Assets->Scripts文件夾下面新建一個名為DestroyByTime的腳本,然后輸入以下代碼:

- 首先我們定義一個公共變量lifeTime,來設(shè)置GameObject的存活時間,時間一到就會被銷毀
- 然后我們在Start方法中,調(diào)用Destroy方法來消除GameObject,第二個參數(shù)就是我們的lifeTime
寫完代碼,保存一下,然后回到Unity編輯器,找到我們的爆炸效果的Prefab,然后添加DestroyByTime腳本

腳本添加完成后,我們再將lifeTime的值設(shè)置為2,運(yùn)行游戲測試一下,這次我們發(fā)現(xiàn)所有的爆炸效果,再生成2秒后就會自己消除了
下集預(yù)告
在下一集中,我們將會學(xué)到:
- 如何給游戲添加背景音樂
- 如何給游戲添加各種音效
- 如何給飛船擊碎障礙后進(jìn)行計分
- 如何判斷游戲結(jié)束
- 如何重新開始游戲
- 如何發(fā)布游戲