
前言
在Unity官方教程 2D UFO(上)中,我們學(xué)會了:
- 新建一個項目Project
- 從資源商店下載素材包
- 新建一個GameObject
- 給UFO添加剛體組件(Rigidbody 2D)和腳本(Script),讓我們通過方向鍵或者WASD來控制UFO移動
我們會看到一個問題,UFO隨便移動幾步就會從平臺掉下去,看也看不見追也追不著。我們可以給平臺添加一圈圍墻來防止這種情況的產(chǎn)生。那么這一節(jié)我們將學(xué)會以下內(nèi)容:
你將學(xué)會操作什么?
- 如何制作圍墻防止UFO從平臺掉下去
- 如何讓攝像機跟隨UFO移動
- 添加“旋轉(zhuǎn)小馬達(dá)”——金幣
- 制作預(yù)制件Prefab
- 實現(xiàn)UFO吃掉金幣
- 添加計分板和游戲結(jié)束提示
- 如何發(fā)布游戲到本地
一、添加圍墻防止UFO掉出平臺
代入到現(xiàn)實生活里面,人和圍墻之間會發(fā)生什么使得人不能直接穿越圍墻到外面去?機智的A同學(xué)可能想到了:物理碰撞。Unity里要想擁有類似圍墻的效果,其實可以通過給Background和Player分別添加碰撞器來實現(xiàn)。
把目光放回到Scene窗口,可以看到Background整個平臺四條邊的格子是特殊顏色和材質(zhì),這個意味著把墻設(shè)置在這4個區(qū)域是比較合適的。那么我們先來添加第一面墻吧!
選中Background,通過Add Component-->Physics 2D-->Box Collider 2D,就可以給平臺添加一個碰撞器組件(墻是方形的所以選擇Box)。

碰撞器默認(rèn)是包裹在Background外圍,在Scene窗口可以看到一圈原諒色在平臺邊緣。把Box Collider 2D組件的Offset內(nèi)的X設(shè)置為-14.26,Size的X改為3.3,可以看到綠色碰撞器區(qū)域變成是在平臺最左側(cè)一列格子,這一面墻就添加好了。

有兩種辦法添加其余三面墻:
- 新增法:和添加第一面那樣,Add Component-->Physics 2D-->Box Collider 2D
- 復(fù)制法:在已有的Box Collider 2D組件的右上角小齒輪里選擇Copy Component,然后再點開一次,選擇Paste Components As New

參考數(shù)值:
- 右:Offset,X為14.26,Y為0;Size,X為3.3,Y為31.64
- 上:Offset,X為0,Y為14.26;Size,X為31.64,Y為3.3
- 下:Offset,X為0,Y為-14.26;Size,X為31.64,Y為3.3

最后一步,給Player添加碰撞器Circle Collider 2D。添加之后雙擊Player可以快速定位到UFO,清晰地看到UFO外面那一圈原諒色。

修改Circle Collider 2D里面的Radius值可以調(diào)整碰撞區(qū)域,在這里設(shè)置為2.15是比較合適的。
這些都完成之后,運行游戲看看,現(xiàn)在UFO不會再飛出去了吧?(o?▽?)o
二、讓攝像機跟隨UFO移動
有豐富游戲經(jīng)驗的同學(xué)都知道,在游戲里面,主角總是處于畫面中心的,換句話說就是攝像機應(yīng)該是跟隨主角移動,保持主角萬眾矚目狀態(tài)。很好,那怎么樣才能讓攝像機跟隨UFO走起來呢?可能機智的A同學(xué)又想到了:把攝像機變成UFO的小弟(子對象),這樣UFO移動,攝像機也會跟著變化。就聽你一次,來試試看

然后運行游戲看看效果怎么樣:

A同學(xué)????
的確,攝像機是跟隨UFO移動了,但是變動地不止是位置,它的角度也跟隨UFO變化了,所以就會如圖一樣出現(xiàn)天旋地轉(zhuǎn)的情況。我們想要的效果只是想讓攝像機的位置跟隨UFO移動,不需要角度變化。這條路走不通,那么只能通過腳本了。
先把Main Camera從Player移出去,然后給攝像機添加一個腳本CameraController,腳本語言是C Sharp。
添加腳本之后記得先把腳本移動到Scripts文件夾,好習(xí)慣盡早養(yǎng)成。
腳本代碼如下:

簡單解讀下代碼含義:
- 首先定義了一個public的GameObject變量player,這個變量是用來告訴程序,攝像機會跟隨哪個GameObject來移動
- 然后定義一個private的Vector3變量offset,這個變量用來記錄游戲初始化的時候,攝像機和UFO之間的距離
- 在Start方法中,攝像機和UFO的位置差賦值給offset變量,有了這個固定值才能在后續(xù)UFO移動的過程中,UFO和攝像機的距離保持不變
- 最后在LateUpdate方法中,把攝像機的新位置變更為球體的新位置加上固定的offset偏移位置
保存腳本,回到Unity編輯器頁面,我們會發(fā)現(xiàn)攝像機的腳本組件中,多了一個Player屬性。

這就是剛才我們在腳本內(nèi)定義的public屬性player。
在Unity腳本里,public屬性會在編輯器內(nèi)顯示,需要填充內(nèi)容才可正常運行。
把UFO拖動到Player屬性中,如圖:

運行游戲,現(xiàn)在再撞墻,攝像機也不會翻跟斗了。

三、添加“旋轉(zhuǎn)小馬達(dá)”——金幣(Pickup)
萬事俱備,就只差一些金幣讓我們的主角UFO去碰撞和拾取了。為了讓金幣更加耀眼,為了UFO能看見,我們讓金幣可以自動旋轉(zhuǎn)起來。
首先我們把Sprites內(nèi)的Pickup拖到Hierarchy窗口,添加一個新的GameObject——Pickup。把Pickup的Sorting Layer改成Pickups之后,因為UFO的Player層級比較高,他倆都在同一個位置(原點),所以我們看不見新增的金幣。為了方便查看金幣,我們可以暫時把UFO隱藏起來。

在這里因為Pickup的名字和位置都剛好不需要修改,所以我沒提到雙標(biāo)動作,但是一般添加GameObject之后最好是要改名和重置Transform的。
之后我們給這個金幣添加一個自動旋轉(zhuǎn)的腳本(記得放到Scripts文件夾),腳本名稱為Rotator,腳本內(nèi)容就一句代碼,如下圖:

簡單地說,就是調(diào)用transform下的Rotate方法按指定的角度(圍繞Z軸旋轉(zhuǎn)45°)旋轉(zhuǎn)一個物體。
放在Update()函數(shù)中的代碼是以幀來執(zhí)行的,因為我們需要金幣的旋轉(zhuǎn)是以秒來執(zhí)行,所以需要乘以Time.deltaTime增量時間。
保存腳本,運行游戲,可以看到金幣變成“旋轉(zhuǎn)小馬達(dá)”了(??ˇ?ˇ?)~
四、制作預(yù)制件Prefab
為了豐富游戲,我們可以做多個金幣讓UFO拾取。這個可以通過制作預(yù)制件(Prefab)來實現(xiàn)。那什么是Prefab呢?舉個可能不是太貼切的例子,就是我們生活中的樣本,比如某輛車的A系列的模型,根據(jù)這個模型可以生產(chǎn)出很多一模一樣的車輛(金幣)。然后只要修改這個模型的參數(shù),那么這個修改就會作用到所有由該模型生產(chǎn)出來的車輛上。
由上可以總結(jié)出預(yù)制件的好處主要是:
一處修改,全部生效:修改Prefab的屬性之后,所有使用這個Prefab的對象的屬性也會跟著變化。
炒雞方便的好嗎?
制作Prefab的方法也很簡單。不過根據(jù)資源管理原則,我們先做兩件事
- 在Assets文件夾創(chuàng)建Prefabs文件夾來存放Prefab文件
- 在Hierarchy窗口下,通過Create-->Create Empty創(chuàng)建一個空的GameObject對象,重命名為Pickups,reset Transform,然后把Pickup拖到Pickups下成為它的子對象。后續(xù)新增的金幣對象都放在其下,好方便管理。

把Pickup拖到Prefabs文件夾,一個預(yù)制件就做好了??梢钥吹?strong>Pickup這個對象的名字也變成藍(lán)色了。


接下來有2個辦法可以通過預(yù)制件制作其他金幣。
- 選中Pickup對象,按CTRL+D可以復(fù)制出一個金幣對象,按多少次就復(fù)制多少個(推薦這個方法)
- 把Prefabs文件夾里面的Pickup預(yù)制件拖到Pickups下就可以生成一個金幣對象
在Scene窗口,鼠標(biāo)左鍵拖動這些金幣可以把它們隨意放到自己覺得合適的地方。

我一共放了13個金幣,中間位置留給UFO,同學(xué)可以把UFO顯示出來了~
五、UFO拾取金幣
接下來要實現(xiàn)UFO碰到金幣的時候就拾取這個功能。關(guān)鍵詞是“碰到”、“拾取”,那么它們分別意味著什么?
- 碰到,也就是碰撞檢測(兩者都存在碰撞組件才能進(jìn)行檢測)
- 拾取,UFO發(fā)現(xiàn)自己碰撞的是金幣而不是墻的時候,讓金幣消失或者不顯示就可以了。
很好,理清了思路,接下來就來看看怎么實現(xiàn)吧。
第1步:金幣Pickup添加碰撞器
選中Pickups下的任意一個對象比如Pickup,通過Add Component-->Physics 2D-->Circle Collider 2D添加好碰撞器,然后雙擊Pickup定位放大,可以很清楚地看到金幣周圍的一圈綠色。

放大的情況下好調(diào)整碰撞器區(qū)域大小。在這里把Radius值設(shè)置為0.93是比較合理的,如果有強迫癥的同學(xué)可以調(diào)整Offset值來調(diào)整中心點。

這樣就給一個金幣添加好了碰撞器了,可是我們還有12個金幣也需要添加碰撞器怎么辦?在這個添加好碰撞器的金幣對象的Inspector窗口右上角有一個Apply按鈕,點一下就可以把這個金幣的設(shè)置同步到其他金幣和預(yù)制件了。

第2步:編寫腳本實現(xiàn)拾取功能
通過查官方API手冊我們可以查到有個名為OnTriggerEnter的方法可以在UFO碰到金幣的時候調(diào)用。另外前面也提到了,UFO是要判斷碰撞到的東西的,因為不能什么東西都拾取,所以需要給拾取的金幣添加一個標(biāo)記(Tag)。
添加Tag的方法:
- 一共13個金幣,每個金幣都添加是很麻煩的事情,這時候可以直接修改預(yù)制件Prefab就可以全部生效了。
- 選中Prefabs內(nèi)的Pickup,然后在Inspector的Tag里面選Add Tag,命名為PickUp(如果列表有PickUp那就無需再加了)


- 然后將預(yù)制件Pickup的Tag設(shè)置為“PickUp”

接下來就是編寫腳本來實現(xiàn)拾取功能。打開UFO的PlayerController腳本,新增以下代碼:

- OnTriggerEnter方法是檢測物理發(fā)生碰撞的時候調(diào)用執(zhí)行里面的代碼,參數(shù)other變量表示UFO碰到的其他2D碰撞器
- 先調(diào)用CompareTag方法判斷碰到的這個對象是否被標(biāo)記了Tag"PickUp",如果是的話則調(diào)用SetActive把這個對象設(shè)置為未激活狀態(tài)(不顯示),也就是false。
編寫完畢,保存腳本,回到Unity編輯器頁面,運行游戲看看。
......機智的A同學(xué)大喊:哈哈哈哈,還是碰撞了,并沒撿起來!
(尷尬.jpg)這是因為,我們沒有把金幣設(shè)置成碰撞觸發(fā)器(Is Trigger)。把金幣設(shè)置成觸發(fā)器之后,在碰撞的時候才會執(zhí)行腳本里面的OnTriggerEnter等方法。在預(yù)制件上勾選之后,再運行游戲,現(xiàn)在可以正常拾取金幣了。

第3步:優(yōu)化性能
現(xiàn)在看起來一切正常,好像并沒有什么問題。但,實際上真的如此么?
- 在Unity的物理引擎中,靜態(tài)的碰撞體(沒有剛體)會被單獨進(jìn)行運算并保存在緩存中,節(jié)約計算資源優(yōu)化性能。
- 所以如果我們移動或者旋轉(zhuǎn)一個不帶剛體的碰撞體(金幣)的話,這個緩存會被重新計算生成,這會耗費一定的資源。
- 所以我們最好給金幣添加上剛體(變成動態(tài)碰撞體),那么它的旋轉(zhuǎn)不會導(dǎo)致緩存在每一幀都被刷新,一定程度上可以達(dá)到節(jié)約資源的目的。
那好,我們給Prefab Pickup 加上Rigidbody 2D,然后運行游戲試試。

就像天上掉下很多金色餃子一樣,金幣都受到了重力掉下來了。的確可以和之前UFO一樣,把Rigidbody 2D的Gravity Scale改成0就不會掉下來,但這只能解決部分問題。我們希望的是金幣不僅僅不受重力影響,也不受其他物理作用力的影響。而這可以通過修改Rigidbody 2D組件的Body Type為Kinematic來實現(xiàn)。

Kinematic:開啟運動學(xué),開啟后不再受力的影響,只能通過Transform屬性來操作。
六、添加計分板和結(jié)束提示
第1步:添加計分板
游戲完成了基本玩法了,但是我們還需要做一個計分板來鼓勵玩家多多拾取金塊。關(guān)鍵詞,“分”和“計分板”,也就是說我們需要做兩個事情:
- 定義一個變量來保存玩家的分?jǐn)?shù)(撿取的金幣數(shù)量)
- 把這個分?jǐn)?shù)顯示在UI上
那么我們來修改下PlayerController腳本,內(nèi)容如下:

三行代碼:定義一個變量count用來保存分?jǐn)?shù),在Start方法里count值初始化為0,最后拾取金幣的時候,count數(shù)量+1。
count++是一種簡寫,效果等同于 count +=1,也等同于count = count +1
分?jǐn)?shù)有了,還需要一個UI展示給玩家。保存腳本,回到Unity編輯器,創(chuàng)建一個UI Text。

改名為Count Text,重置下Transform,雙擊Count Text定位放大,鼠標(biāo)左鍵把它拖到合適的位置,比如屏幕左上角。

Inspector的Text組件內(nèi)的屬性可以修改UI的展現(xiàn)。Text是默認(rèn)文字內(nèi)容,F(xiàn)ont Size是字體大小,Color是字體顏色,可以自己試著修改。
接下來再次修改PlayerController:

- 最上面的命名空間,我們需要引入UnityEngine.UI,這樣后面代碼才會識別Text類型的變量
- 定義countText變量來保存UI Count Text
- 接著我們在Start方法中調(diào)用setCountText方法,來更新countText的內(nèi)容
- 然后我們在每次UFO拾取金幣的時候,也更新countText的內(nèi)容
- 最后是我們定義的setCountText方法,里面調(diào)用的ToString方法是讓int類型的count轉(zhuǎn)換成字符串
保存腳本,回到Unity,把Count Text UI 拖入到Player里面的Count Text屬性框里面。

做完這些運行游戲看看效果!
第2步:添加游戲結(jié)束提示
為了讓游戲更加友好,在玩家拾取完畢所有金幣之后,應(yīng)該提示玩家通關(guān)了。首先我們也需要先創(chuàng)建一個文本UI(Win Text),字體18號,黃色,位置在UFO上方,這應(yīng)該是個不錯的選擇。

回到PlayerController添加代碼:

- 定義winText變量來保存UI Win Text
- 接著我們在Start方法中初始化winText為空字符串,因為游戲開始的時候這個內(nèi)容是不顯示的
- 最后我們在setCountText方法里面,判斷當(dāng)分?jǐn)?shù)大于等于13的時候,就更新winText的內(nèi)容為“You win !”
這個13是因為我的金幣數(shù)量最多是13,同學(xué)可以根據(jù)自己的金幣數(shù)量來修改這個數(shù)字。
保存腳本,回到Unity,把Win Text UI 拖入到Player里面的Win Text屬性框里面,再運行游戲就可以看到效果了。
七、本地發(fā)布游戲
游戲制作完畢,可以發(fā)布游戲到本地了。呼(?>?<)☆不容易啊,不過最后一步最簡單......保存場景,通過菜單欄File-->Build Settings打開發(fā)布頁面。

- Platform選擇第一項,PC,Mac&Linux Standalone
- 點擊Add Open Scenes按鈕,把當(dāng)前場景添加進(jìn)去并且勾選
- 點擊Build按鈕,選擇存放路徑,就可以完成發(fā)布了
找到保存路徑下的exe文件雙擊運行就可以開始撿錢了!ヾ(?°?°?)??