自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何使用Unity3D+C#開發(fā)炸彈人游戲

譯文
移動開發(fā) 游戲開發(fā)
炸彈人游戲是上世紀80年代廣泛流行的一個2D游戲,本文介紹如何使用Unity3D創(chuàng)建像炸彈人這樣的基本類型的游戲,包括一些粒子系統(tǒng)用于炸彈與爆炸效果。

簡介

炸彈人游戲是上世紀80年代廣泛流行的一個2D游戲,本文創(chuàng)建的是一個基本型的此游戲的Unity3D版本。

通過本游戲,你可以實現(xiàn)如下功能:

  • 投擲炸彈并把它放到特定位置
  • 通過光線跟蹤技術(shù)激活炸彈
  • 處理與玩家的爆炸碰撞
  • 處理與炸彈的爆炸碰撞
  • 游戲結(jié)局處理

準備工作

首先,請下載一個我為本文游戲建立的初始示例項目,然后把它放到一個你指定的位置。

然后,使用Unity3D打開這個項目,注意到Assets文件夾下包含了好多的子文件夾,如圖所示。

這里具體說一下各個文件夾的主要功能:

  • Animation Controllers:存儲著游戲控制器部分,包括的邏輯部分。
  • Materials:包含構(gòu)建各關(guān)卡場景所需要的塊(Block)材質(zhì)。
  • Models:存儲玩家、關(guān)卡及炸彈模型,及其相關(guān)材質(zhì)。
  • Music:存儲游戲的音效文件。
  • Physics Materials:存儲玩家的物理材質(zhì)數(shù)據(jù),它們是一些特殊類型的材質(zhì),用于實現(xiàn)特定的物理屬性。在本教程中,用于使玩家在無摩擦情況下輕松地在關(guān)卡中穿越。
  • Prefabs:包含炸彈及爆炸的預(yù)制數(shù)據(jù)。
  • Scenes:對應(yīng)于游戲場景數(shù)據(jù)。
  • Scripts:包含游戲的啟動腳本,其中添加的大量注釋將有利于讀者閱讀源碼。
  • Sound Effects:包含炸彈及爆炸效果相關(guān)的聲效文件。
  • Textures:包含兩個玩家的紋理數(shù)據(jù)。

投擲炸彈

如果你還沒有打開游戲工程,請抓緊打開,然后試著運行一下此程序。沒有其他問題的話,你會觀察到如圖所示的情形:

你會注意到,游戲中的兩個玩家可以通過鍵盤上的WASD四個字符鍵或者四個箭頭鍵驅(qū)動,使其沿著游戲地圖運動。

通常,當按下空格鍵時紅色玩家會在其腳下安置一枚炸彈,而另一個玩家也能夠做同樣的事情——只是通過按回車鍵實現(xiàn)。

然而,目前我們還沒有實現(xiàn)這一功能。為此,你需要先編寫放置炸彈的代碼?,F(xiàn)在,請你使用自己喜歡的代碼編輯器打開腳本文件Player.cs。

此腳本負責處理所有的玩家運動及動畫邏輯,還包含一個方法DropBomb,當關(guān)聯(lián)游戲?qū)ο?GameObject)bombPrefab時,它用于檢測目的。

 

  1. private void DropBomb() { 
  2. if (bombPrefab) { //Check if bomb prefab is assigned first 

為了實現(xiàn)一個炸彈掉落在玩家下面的效果,在if語句中添加下面的代碼:

  1. Instantiate(bombPrefab, myTransform.position, bombPrefab.transform.rotation); 

上述代碼將在玩家腳下生成炸彈(隨著玩家的運動路徑的變化,將生成成串的炸彈)?,F(xiàn)在,運行一下游戲工程,你會觀察到如下圖所示效果:

目前,效果不錯吧!

但是,還有一個小問題:炸彈投擲的方式如何?如果是無論在哪里你都能放炸彈的話,當你需要計算爆炸應(yīng)該發(fā)生的位置時就會帶來一些問題。

接下來,本教程將向你具體介紹如何實現(xiàn)爆炸的所有細節(jié)。

炸彈定位

下一步任務(wù)是確保炸彈在丟掉時能夠附著到相應(yīng)位置,從而實現(xiàn)炸彈很好地與地板上的網(wǎng)格對齊。由于我們的設(shè)計中網(wǎng)格上的每個圖塊大小是 1 × 1,所以進行此更改是相當容易的。

打開文件Player.cs,編輯一下Instantiate()函數(shù),像下面這樣:

 

  1. Instantiate(bombPrefab, new Vector3(Mathf.RoundToInt(myTransform.position.x), 
  2. bombPrefab.transform.position.y, Mathf.RoundToInt(myTransform.position.z)), 
  3. bombPrefab.transform.rotation); 

注意,這里函數(shù)Mathf.RoundToInt調(diào)用中使用了玩家位置的x和z兩個參數(shù)值,每一個浮點類型值被轉(zhuǎn)換為一個整型值,這就可以實現(xiàn)炸彈很好地與地板上的網(wǎng)格對齊的效果:

現(xiàn)在,你可以再次啟動工程來運行一下,你會觀察到當投擲炸彈時,這些炸彈恰好能夠?qū)R網(wǎng)格:

雖然把炸彈投擲到地圖上是很有趣的,但你知道真正有趣的事是如何實現(xiàn)爆炸!為此,我們再來添加一些功能。

創(chuàng)建爆炸效果

首先,我們要創(chuàng)建一個新的腳本文件:

(1)從Project視圖下選擇Scripts文件夾;

(2)按下Create按鈕;

(3)選擇“C# Script”;

(4)把腳本文件命名為Bomb即可。

現(xiàn)在,把Bomb.cs腳本關(guān)聯(lián)到預(yù)制Bomb上:

(1)在Prefabs文件夾中選擇GameObject Bomb;

(2)點擊按鈕“Add Component”;

(3)在搜索框中輸入“bomb”;

(4)選擇你剛剛創(chuàng)建的腳本Bomb.cs;

(5)打開此腳本文件,然后在其Start()方法中輸入如下代碼:

  1. Invoke("Explode", 3f); 

此方法使用了兩個參數(shù),第一個是將要調(diào)用的方法名稱,第二個是在調(diào)用此方法時需要延遲的時間數(shù)。在本例中,想實現(xiàn)炸彈在3秒內(nèi)爆炸的效果。我們將在后面添加這個Explode方法的具體內(nèi)容。

現(xiàn)在,只是在Update()方法下面添加這個方法占位符形式(目前為空):

 

  1. void Explode() { 

在生成任何GameObject Explosion之前,還需要創(chuàng)建一個公共類型的GameObjet對象,以便進行預(yù)制Explosion的賦值。恰好在Start()方法上面定義如下代碼:

  1. public GameObjectexplosionPrefab; 

保存此文件,然后從Prefabs文件夾下選擇預(yù)制Bomb,然后把預(yù)制Explosion拖動到“Explosion Prefab”選項后面空白處。

完成這一操作后,返回到編輯器中?,F(xiàn)在開始編寫更有意思的代碼。

在方法Explode()中,添加如下代碼行:

 

  1. Instantiate(explosionPrefab, transform.position, Quaternion.identity); //1 
  2. GetComponent<MeshRenderer>().enabled = false; //2 
  3. transform.FindChild("Collider").gameObject.SetActive(false); //3 
  4. Destroy(gameObject, .3f); //4 

上述代碼實現(xiàn)如下功能:

1.在炸彈位置觸發(fā)爆炸;

2.禁用網(wǎng)絡(luò)渲染器(mesh render),使炸彈不可見;

3.禁用碰撞器,從而允許玩家在爆炸中移動與行走;

4.在0.3秒后拆除炸彈;這可以確保在刪除GameObject之前所有爆炸都會觸發(fā)。

現(xiàn)在,保存腳本Bomb.cs,返回到編輯器嘗試再玩一下游戲。放下一些炸彈并觀察一下它們爆炸時良好的效果,參考下圖。

設(shè)置爆炸音效

為了創(chuàng)建理想的爆炸效果,你需要創(chuàng)建一個協(xié)程。

「補充」協(xié)程本質(zhì)上是一個函數(shù),允許你暫停執(zhí)行并將控制返回到Unity3D。在以后的某個時間點處該函數(shù)將從上次離開的位置恢復執(zhí)行。

人們經(jīng)?;煜齾f(xié)程與多線程。其實,它們是不同的:協(xié)程運行在同一個線程中,并能夠在某中間點處及時恢復執(zhí)行。若要了解更多的關(guān)于協(xié)程及其定義相關(guān)信息,請查閱相關(guān)的Unity文檔(http://docs.unity3d.com/Manual/Coroutines.html)。

現(xiàn)在,返回到代碼編輯器中修改腳本Bomb.cs,在函數(shù)Explode()下面添加一個名字為CreateExplosions的IEnumberator:

 

  1. private IEnumeratorCreateExplosions(Vector3 direction) { 
  2. return null // placeholder for now 

創(chuàng)建協(xié)程

現(xiàn)在,請把下面四行代碼添加到函數(shù)Explode()內(nèi)部的Instantiate調(diào)用與MeshRender禁用之間:

 

  1. StartCoroutine(CreateExplosions(Vector3.forward)); 
  2. StartCoroutine(CreateExplosions(Vector3.right)); 
  3. StartCoroutine(CreateExplosions(Vector3.back)); 
  4. StartCoroutine(CreateExplosions(Vector3.left)); 

這里的StartCoroutine調(diào)用將針對游戲場景中的每個方向觸發(fā)CreateExplosions。

現(xiàn)在,更有趣的時刻到了。在方法CreateExplosions()內(nèi)部加入如下代碼:

 

  1. //1 
  2. for (inti = 1; i< 3; i++) { 
  3.  
  4. //2 
  5. RaycastHit hit; 
  6.  
  7. //3 
  8. Physics.Raycast(transform.position + new Vector3(0,.5f,0), direction, out hit, i, levelMask); 
  9.  
  10. //4 
  11. if (!hit.collider) { 
  12. Instantiate(explosionPrefab, transform.position + (i * direction), 
  13.  
  14. //5 
  15. explosionPrefab.transform.rotation); 
  16.  
  17. //6 
  18. else { 
  19.  
  20. //7 
  21. break; 
  22.  
  23. //8 
  24. yield return new WaitForSeconds(.05f); 

這段代碼看起來相當復雜,但實際上相當簡單。詳細解釋如下:

1.通過for循環(huán)來遍歷你想要爆炸覆蓋的每個單位距離。在本例情況下,爆炸將達到兩米的距離。

2.RaycastHit對象包含有關(guān)Raycast擊中的是什么對象及擊中位置的所有信息,當然也可能沒有擊中。

3.上述代碼中非常重要的代碼行是StartCoroutine調(diào)用,這個調(diào)用中實現(xiàn)從炸彈中心朝你通過的方向發(fā)出raycast。然后,它將結(jié)果輸出到RaycastHit對象。I 參數(shù)指示射線走過的距離。最后,代碼中使用命名為levelMask的層蒙版(LayerMask)來確保射線只檢查當前關(guān)卡中的塊而忽略檢查玩家及其他的碰撞對象。

4.如果raycast沒有撞到任何東西,那么說明這個塊(Block)是一個自由塊。

5.在raycast檢查的位置產(chǎn)生爆炸。

6.Raycast擊中塊。

7.一旦raycast擊中一個塊,它就跳出for循環(huán)。這將確保爆炸不會跨越墻。

8.在進行下一個for循環(huán)迭代前等待0.05秒。這將使爆炸呈現(xiàn)向外擴展的效果而更具有說服力。

下圖給出的是上面添加代碼后的動畫效果:

注意,下圖中的紅線是raycast。它圍繞炸彈檢查一段自由空間距離;如果發(fā)現(xiàn)存在碰撞,那么將產(chǎn)生爆炸。當它擊中塊時,它并不產(chǎn)生任何東西并停止在那個方向上的檢查。

現(xiàn)在,你該明白了為什么炸彈需要附著到網(wǎng)格中各小格子中心了吧。如果炸彈能去任何地方,那么在一些邊緣情況下,raycast會擊中塊卻并不產(chǎn)生任何爆炸,因為它沒有正確地進行水平對齊。

添加遮罩層

在Bomb代碼中還存在一個錯誤:事實上LayerMask并不存在。因此,現(xiàn)在就在explosionPrefab變量聲明的下面,再添加一行代碼,如下:

 

  1. public GameObjectexplosionPrefab; 
  2. public LayerMasklevelMask; 

LayerMask通常使用raycasts技術(shù)有選擇地篩選出特定圖層。在本例情況下,你只需要篩選出塊部分,所以,raycasts技術(shù)并沒有做什么事。

保存Bomb腳本并返回到Unity編輯器。單擊右上角的Layers按鈕并選擇Edit Layers...

現(xiàn)在,請點擊User Layer 8旁邊的文本框并輸入“Blocks”。這樣就定義了你可以使用的新層。

在層次視圖中,選擇GameObject Blocks,如下圖所示:

把圖層改變?yōu)槟銊倓倓?chuàng)建的圖層Blocks,如下圖所示:

當出現(xiàn)“Change Layer”對話框時點擊“Yes,change children”按鈕,以便應(yīng)用于地圖上所有散布的黃色長方體塊。

最后,從Prefabs文件夾下選擇預(yù)制Bomb,并把遮罩層改成Blocks。

現(xiàn)在,再次運行一下游戲場景并投擲幾枚炸彈。你會觀察到爆炸效果比以前好多了:良好地分布于各長方體塊之間!

恭喜你,你已經(jīng)攻克了本游戲中最困難的編碼部分。剩下的是為游戲添加一些附加效果。

鏈式反應(yīng)

當一枚炸彈爆炸時會接觸到另一個炸彈,這枚相鄰的炸彈也應(yīng)該爆炸,這將產(chǎn)生一種更令人驚喜的效果。

值得欣喜的是,上述效果并不難實現(xiàn)。

現(xiàn)在打開腳本文件Bomb.cs,然后在方法CreateExplosions()下面添加一個新的方法OnTriggerEnter:

 

  1. public void OnTriggerEnter(Collider other) { 

OnTriggerEnter方法是MonoBehaviour中一個預(yù)定義的方法,在觸發(fā)器碰撞器與剛體碰撞時激活執(zhí)行。碰撞器參數(shù)是other,對應(yīng)于進入觸發(fā)器的游戲物體(GameObject)的碰撞器。

在本例情況下,你需要檢查碰撞對象,并確定當該對象是一個爆炸對象時使之爆炸。

首先,你需要知道是否發(fā)生炸彈爆炸。需要首先聲明exploded變量,因此在levelMask變量聲明下面添加以下聲明:

  1. private bool exploded = false

然后,在方法OnTriggerEnter()內(nèi)部添加如下代碼:

 

  1. if (!exploded&&other.CompareTag("Explosion")) { // 1 & 2 
  2. CancelInvoke("Explode"); // 2 
  3. Explode(); // 3 

這段代碼做了三件事情:

1.檢查炸彈是否已經(jīng)爆炸了;

2.檢查觸發(fā)器碰撞器是否已經(jīng)有標簽Explosion;

3.通過投擲炸彈取消已經(jīng)調(diào)用的Explode調(diào)用——如果不這樣做,炸彈可能會爆炸兩次;

4.實現(xiàn)爆炸。

現(xiàn)在你已經(jīng)定義了變量,但是還沒有作任何修改。而最合乎邏輯的地方是在Explode()函數(shù)中實現(xiàn)這一操作(應(yīng)當在禁用組件MeshRenderer之后),代碼如下:

 

  1. ... 
  2. GetComponent<MeshRenderer>().enabled = false
  3. exploded = true
  4. ... 

現(xiàn)在準備好了一切,請保存一下剛才的文件修改,然后再次運行一下工程。再次投擲一枚炸彈,并連續(xù)在其周圍投擲炸彈,觀察效果:

最后剩下的事情是處理玩家對于爆炸的反應(yīng)情況,以及游戲結(jié)局處理邏輯。

游戲結(jié)局處理

打開文件Player.cs。目前還沒有定義變量來表示玩家的死活;因此,在腳本頂部添加一個布爾變量,如下所示:

  1. public cool dead=false

這個變量用于跟蹤是否玩家在爆炸以后死亡。

接下來,在其他變量聲明后面添加如下變量聲明:

  1. public GlobalStateManagerGlobalManager; 

注意,到現(xiàn)在在方法OnTriggerEnter()內(nèi)部已經(jīng)能夠檢查是否玩家被炸彈擊中,但目前實現(xiàn)的僅僅是通過控制臺窗口輸出這一消息。因此,現(xiàn)在請將如下代碼添加到Debug.Log調(diào)用后面:

 

  1. dead = true; // 1 
  2. GlobalManager.PlayerDied(playerNumber); // 2 
  3. Destroy(gameObject); // 3 

這段代碼實現(xiàn)如下功能:

1.修改變量dead,以便跟蹤玩家死亡的消息;

2.通知全局狀態(tài)管理器玩家已經(jīng)死亡;

3. 銷毀玩家對象GameObject。

現(xiàn)在,保存一下文件并返回到Unity編輯器中。你需要把GlobalStateManager連接到兩個玩家:

(1)在層次窗口內(nèi),選擇兩個Player GameObject。

(2)把全局狀態(tài)管理器GameObject拖動到它們的Global Manager選項處。

再次運行游戲場景,確保至少有一個玩家被炸彈擊中,參考下圖。

每一個遭遇到爆炸的玩家都會立即死亡。

但是,目前為止游戲并不知道誰贏了,因為GlobalStateManager還沒有使用它收到的信息。下面來討論這件事情。

定義贏家

打開文件GlobalStateManager.cs。為了使GlobalStateManager能夠跟蹤玩家的死亡,還需要定義兩個變量。在函數(shù)PlayerDied()上面加上下面的定義:

 

  1. private intdeadPlayers = 0; 
  2. private intdeadPlayerNumber = -1; 

首先,變量deadPlayers會存儲死亡的玩家數(shù)量。一旦第一個玩家死亡,變量deadPlayerNumber即被修改,此變量也表示了是哪一位玩家這種額外信息。

準備好了上面變量后,現(xiàn)在加入實際邏輯。在函數(shù)PlayerDied()中加入如下代碼:

 

  1. deadPlayers++; // 1 
  2. if (deadPlayers == 1) { // 2 
  3. deadPlayerNumber = playerNumber; // 3 
  4. Invoke("CheckPlayersDeath", .3f); // 4 

 

這段代碼的功能是:

1.添加一個死亡玩家;

2.進一步判斷是否這是第一個死亡玩家…

3.把死亡玩家數(shù)設(shè)置為首先死亡的玩家;

4.檢查是否另一個玩家也死亡了,還是在0.3秒后僅起了一些爆炸塵埃而沒有死亡。

最后的一點時間延遲對于繪制檢查來說很重要。如果立即進行檢查,你可能發(fā)現(xiàn)不了有人死亡,而0.3秒對于判斷是否每一個人都死亡了已經(jīng)足夠了。

輸贏判定

現(xiàn)在,請在GlobalStateManager腳本中添加一個新方法CheckPlayersDeath:

 

  1. void CheckPlayersDeath() { 
  2. // 1 
  3. if (deadPlayers == 1) { 
  4. // 2 
  5. if (deadPlayerNumber == 1) { 
  6. Debug.Log("Player 2 is the winner!"); 
  7. // 3 
  8. else { 
  9. Debug.Log("Player 1 is the winner!"); 
  10. // 4 
  11. else { 
  12. Debug.Log("The game ended in a draw!"); 

上述條件語句的功能列舉如下:

1.只有一個玩家死亡,則判定他是輸家;

2.玩家1死亡了,那么玩家2是贏家;

3.玩家2死亡了,那么玩家1是贏家;

4.兩個玩家都死亡了,那么這是一場平局。

現(xiàn)在,再保存并運行一下你的工程試試吧,參考下圖:

剩下的話

下載工程代碼并進行詳細研究吧!

你通過本文了解了如何使用Unity3D創(chuàng)建像炸彈人這樣的基本類型的游戲。

本文使用了一些粒子系統(tǒng)用于炸彈與爆炸效果。更多的有關(guān)信息,請參考Unity3D官方文檔。

最后,強烈建議你做如下增強性修改:

(1)可以使炸彈能夠被推動,這樣當炸彈靠近你時你可以逃跑,而把炸彈推到你的對手身上;

(2)限制可以投擲的炸彈數(shù)量;

(3)加入重新啟動游戲功能;

(4)伴隨爆炸加入可破裂的場景中的塊(Blocks);

(5)你可以增加一些有趣的裝備;

(6)多加幾條命,以及使用某種方式來進行購買;

(7)創(chuàng)建漂亮的UI元素來顯示玩家贏了什么東西;

(8)探討某種方法來添加更多的玩家,等等。

責任編輯:武曉燕 來源: 51CTO.com
相關(guān)推薦

2016-06-28 12:55:28

移動·開發(fā)技術(shù)周刊

2012-12-24 09:11:58

iOSUnity3D

2012-12-24 09:04:04

iOSUnity3D

2013-04-25 09:56:24

unity3D手機游戲引擎

2013-04-25 00:06:06

unity3D手機游戲引擎

2023-08-18 08:00:00

游戲開發(fā)3D模型

2013-04-25 10:03:07

unity3D手機游戲引擎

2012-12-24 08:48:25

iOSUnity3D

2012-12-24 08:46:50

iOSUnity3D

2014-04-17 11:05:30

2012-12-24 08:45:19

iOSUnity3D

2012-12-24 08:40:12

2012-12-24 08:50:21

iOSUnity3D

2013-04-25 09:08:39

unity3D手機游戲引擎

2012-05-14 16:30:10

UNITY摩卡世界3D移動游戲

2012-12-24 08:57:35

iOSUnity3D

2012-12-24 09:01:41

iOSUnity3D

2010-09-08 11:26:26

Windows PhoXNA 4.0 3D游戲開發(fā)

2012-12-24 09:17:12

iOSUnity3D
點贊
收藏

51CTO技術(shù)棧公眾號