成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何使用Unity3D+C#開發炸彈人游戲

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

簡介

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

通過本游戲,你可以實現如下功能:

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

準備工作

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

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

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

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

投擲炸彈

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

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

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

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

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

 

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

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

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

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

目前,效果不錯吧!

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

接下來,本教程將向你具體介紹如何實現爆炸的所有細節。

炸彈定位

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

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

 

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

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

現在,你可以再次啟動工程來運行一下,你會觀察到當投擲炸彈時,這些炸彈恰好能夠對齊網格:

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

創建爆炸效果

首先,我們要創建一個新的腳本文件:

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

(2)按下Create按鈕;

(3)選擇“C# Script”;

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

現在,把Bomb.cs腳本關聯到預制Bomb上:

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

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

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

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

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

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

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

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

 

  1. void Explode() { 

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

  1. public GameObjectexplosionPrefab; 

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

完成這一操作后,返回到編輯器中。現在開始編寫更有意思的代碼。

在方法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 

上述代碼實現如下功能:

1.在炸彈位置觸發爆炸;

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

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

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

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

設置爆炸音效

為了創建理想的爆炸效果,你需要創建一個協程。

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

人們經常混淆協程與多線程。其實,它們是不同的:協程運行在同一個線程中,并能夠在某中間點處及時恢復執行。若要了解更多的關于協程及其定義相關信息,請查閱相關的Unity文檔(http://docs.unity3d.com/Manual/Coroutines.html)。

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

 

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

創建協程

現在,請把下面四行代碼添加到函數Explode()內部的Instantiate調用與MeshRender禁用之間:

 

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

這里的StartCoroutine調用將針對游戲場景中的每個方向觸發CreateExplosions。

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

 

  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循環來遍歷你想要爆炸覆蓋的每個單位距離。在本例情況下,爆炸將達到兩米的距離。

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

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

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

5.在raycast檢查的位置產生爆炸。

6.Raycast擊中塊。

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

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

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

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

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

添加遮罩層

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

 

  1. public GameObjectexplosionPrefab; 
  2. public LayerMasklevelMask; 

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

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

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

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

把圖層改變為你剛剛創建的圖層Blocks,如下圖所示:

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

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

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

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

鏈式反應

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

值得欣喜的是,上述效果并不難實現。

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

 

  1. public void OnTriggerEnter(Collider other) { 

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

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

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

  1. private bool exploded = false

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

 

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

這段代碼做了三件事情:

1.檢查炸彈是否已經爆炸了;

2.檢查觸發器碰撞器是否已經有標簽Explosion;

3.通過投擲炸彈取消已經調用的Explode調用——如果不這樣做,炸彈可能會爆炸兩次;

4.實現爆炸。

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

 

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

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

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

游戲結局處理

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

  1. public cool dead=false

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

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

  1. public GlobalStateManagerGlobalManager; 

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

 

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

這段代碼實現如下功能:

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

2.通知全局狀態管理器玩家已經死亡;

3. 銷毀玩家對象GameObject。

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

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

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

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

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

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

定義贏家

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

 

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

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

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

 

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

 

這段代碼的功能是:

1.添加一個死亡玩家;

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

3.把死亡玩家數設置為首先死亡的玩家;

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

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

輸贏判定

現在,請在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.兩個玩家都死亡了,那么這是一場平局。

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

剩下的話

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

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

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

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

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

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

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

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

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

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

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

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

責任編輯:武曉燕 來源: 51CTO.com
相關推薦

2016-06-28 12:55:28

移動·開發技術周刊

2012-12-24 09:11:58

iOSUnity3D

2012-12-24 09:04:04

iOSUnity3D

2013-04-25 09:56:24

unity3D手機游戲引擎

2023-08-18 08:00:00

游戲開發3D模型

2013-04-25 00:06:06

unity3D手機游戲引擎

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

2012-05-14 16:30:10

UNITY摩卡世界3D移動游戲

2012-12-24 08:57:35

iOSUnity3D

2012-12-24 09:01:41

iOSUnity3D

2013-04-25 09:08:39

unity3D手機游戲引擎

2010-09-08 11:26:26

Windows PhoXNA 4.0 3D游戲開發

2012-12-24 08:52:44

iOSUnity3D
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品免费一区二区三区 | 日韩国产在线 | 日日天天| 日韩在线视频精品 | 国产精品一二三区在线观看 | 日本在线小视频 | 99久久精品国产一区二区三区 | 亚洲精品一二三区 | 亚洲人成在线观看 | 日本成人免费观看 | 美女三区 | 9191成人精品久久 | 成人免费视频观看视频 | 欧美国产日韩一区二区三区 | 成人二区| 久久久久国产精品免费免费搜索 | 91麻豆精品国产91久久久久久 | 热久久国产 | 四季久久免费一区二区三区四区 | 日韩午夜 | 欧美二区乱c黑人 | 欧美激情精品久久久久 | 久久精品中文 | 成人精品鲁一区一区二区 | 一区二区三区免费在线观看 | 国产成人在线看 | 91麻豆精品国产91久久久久久 | 午夜视频一区 | 欧美日韩在线一区二区 | 国产中文一区二区三区 | 2020国产在线| 欧美一区二区三区在线观看 | 国产区在线看 | 久草视频观看 | 噜啊噜在线 | av中文字幕在线观看 | 久久国产精品一区二区三区 | 久久精品小视频 | 美女天天操 | 色一级 | 午夜精品久久久久久 |