[Zenva 免費部落格式課程]

在本系列課程中,我們將構建一個多人炸彈超人( Bomberman )遊戲。我們的遊戲將有一個標題場景(title scene),這將允許玩家(player)創建或加入遊戲。此外,它將有一個戰鬪場景(battle scene),玩家將以競爭的方式和對方打鬪。

第一部分的教學中,我們完成Bomberman遊戲中基本的遊戲功能。於這第二部分,我們將完成單人遊戲功能的實現,如:投擲炸彈、製造爆炸,並為玩家增加許多條命。然後,在下一個教學中,我們將添加多人遊戲並完成系列遊戲。

為了讓你有辦法聽懂這個教學,你應該熟悉以下概念:

  • C#程式設計
  • 基本的Unity 概念,如如何輸入資產,建立預製和添加組件
  • 基本平鋪地圖製作,例如添加圖塊和建圖塊圖層

請先完成第1部份,在看這一篇。

資產版權

本教學中使用的資產由 Cem Kalyoncu / cemkalyoncu和Matt Hackett / richtaur 創建,並由 “usr_share” 提供,通過 Creative Commons 許可證,允許在歸屬下進行商業使用。你可以在 http://opengameart.org/content/bomb-party-the-complete-set 或以下原始碼的下載連結。

原始碼檔案

你可以在來信 info@esast.com , 主旨 Bomberman, 給我們你的email, 我們將用Dropbox與你共享. Soft & Share已跟Zenva要到原始碼資料

放下炸彈

到現在,我們的玩家可以在戰鬪地圖移動了。然而,仍然無法在遊戲中放下炸彈。這是我們現在要添加的。

我們首先需要做的是建一個炸彈預製(prefab)。那我們就建一個新的預製,命名為"Bomb"。這個預製將需要一個 Sprite Renderer 、一個 Animator(你可以用先前做Player Animator相同的方式)和一個 Box Collider 2D。Box Collider將是觸發器(trigger),因此請檢查 Trigger 框。這樣一來,當炸彈剛落下時,它不會將玩家推開。另外,正如我們與其他戰鬪場景物件一樣,你需要正確設置其比例並將Sprite Renderer中的排序圖層(Sorting Layer)設為遊戲(Game)層。

spriterender.png

現在我們需要創建炸彈爆炸動畫。我們已經建了 BombAnimator,因此你可以創建一個名為Explosion的新動畫,並將其拖動到 Animator 編輯器中的 BombAnimator。

BombAnimator 將比做一個玩家(player one)簡單得多。它只會有爆炸動畫,所以我們不需要添加任何參數(parameters)或轉換(transitions)。但是,我們仍然需要創建這個動畫。

為了輕鬆編輯動畫,你可以暫時向遊戲添加一個炸彈。所以,選中“Bomb”物件後,打開動畫(Animation)編輯器來編輯 Explosion 動畫。然後將所有的炸彈精靈片(spritesheet) 框拖到它那,如下圖所示。記住要正確設好樣本數量。完成編輯動畫後,你可以從遊戲中刪除Bomb物件。

addproperty

現在我們有一個可行的炸彈預製,我們將允許玩家在遊戲中放下炸彈。

為了做到這一點,我們將要建如下的 BombDropping 腳本。在此腳本的更新方法中,我們將採用 Space 鍵(或任何其他你喜歡的鍵)。如果按下該鍵,腳本將呼叫 DropBomb 方法。

DropBomb 方法將從其預製中實例化一個新的Bomb(預製是腳本的一個屬性)。新炸彈的位置將與先前新增一個玩家(player)相同。

最後,我們將此腳本添加到Player 預製(prefab)。

bombdropping

而且運用那,你已可以嘗試玩遊戲和放下炸彈。但是,你將注意到,由於我們將其碰撞器(colliders)設為觸發器(trigger),玩家(Player)不會與炸彈碰撞。我們現在要修復這問題,因為我們允許炸彈爆炸。

battle_with_bombs

製作爆炸

只要Bomb的碰撞器(collider)是觸發器(trigger),玩家就不會碰撞它。但是,如果我們不勾選 “Is Trigger”框,當玩家(Player)放下一個炸彈時將被推開,因為它們會相互碰撞。

解決這個問題的一種方法是炸彈創建時有觸發碰撞器。但是,一旦玩家不再與炸彈碰撞了,我們將炸彈碰撞器改為非觸發。從這一時起,玩家和炸彈將以正常的模式碰撞。

我們將在一個名為 BombExplosion 的新腳本中執行此操作。這個腳本也將用於引爆炸彈,但現在我們只需要執行以下操作:我們將實現 OnTriggerExit2D 方法,當它被呼叫時,它會將炸彈碰撞器從此更改為非觸發器。當另一個物件的碰撞器離開Bomb觸發器時,OnTriggerExit2D方法被呼叫。也就是說,一旦玩家沒和炸彈位置重疊時這個方法馬上被呼叫。

onetriggerexit2d.png

我們的下一步是在動畫結束時引爆炸彈。我們先來做一個 Explosion 預製。然後,我們可以在BombExplosion 腳本中添加一個 Explode 方法以製作爆炸。

所以,做一個新的預製,稱之為 Explosion。這個預製將有一個Sprite Renderer(在遊戲排序圖層中),一個 Box Collider 2D 和一個 Rigidbody2D。 請注意,Explosion 碰撞器也將是一個觸發器。這是因為我們不希望爆炸與其他物件(如player)進行物理的互動。然而,它需要一個Rigidbody2D,以便可以與遊戲中的牆壁做碰撞,因為Unity只有當至少有一個物件具有Rigidbody(另一種選擇是將一個剛體添加到牆壁)時,才會產生碰撞。 但是,請注意,Explosion Rigidbody是一個運動學(Kinematic),因為我們不希望爆炸在遊戲中移動。

現在我們有Explosion預製,我們可以在 BombExplosion 腳本中做出許多爆炸。首先,我們來建一個Explode方法,如下所示。先設定爆炸會在炸彈的位置發生。此外,這個爆炸應該在一段時間後被毀滅,所以我們要做一個稱為Destroy的方法,給定爆炸持續時間。最後,爆炸將向四個方向(左,右,上,下)爆炸,並自我毀滅。 我們使用 CreateExplosions 方法完成爆炸的製作,現在就開始實現這個方法。

譯者註: 想更清楚 Unity 的 collider、trigger、kinematic 清楚的話,可以參考這篇文章

gameobject.png

CreateExplosions方法如下所示。這種方法會在給定的方向產生爆炸。爆炸的數量依照腳本的explosionRange屬性。那麼,它將從0迭代到製造出來的爆炸次數。然而,一旦發現牆壁或磚塊,它應該停止創造爆炸。如果在爆炸過程中碰到一堵磚塊,則該磚塊應該被銷毀。

我們可以使用Unity中的Physics2D.OverlapBox方法來做。此方法接收Box、角度 、ContactFilter 和 Colliders列表作為參數。然後,它將以所有和查詢框框(box)重疊的碰撞機來填充Colliders列表。這樣,我們可以檢查爆炸區域是否已被牆壁或磚塊佔據。在我們的情況下,角度將為0,我們不會使用任何特殊的 ContactFilter,所以我們只需要擔心這個框框(box)。

框框(box)將是爆炸佔據的區域,所以我們可以使用爆炸位置(explosionPosition)和爆炸尺寸(explosionDimension)值。一旦我們有碰撞列表,我們會重複步驟執行到找到牆壁或磚塊為止。如果我們找到一堵牆或磚塊,我們設置一個變量為真,並打破循環。如果我們找到一堵磚塊,我們就會摧毀它。最後,在外部循環中,如果我們找到了一堵磚或牆,我們也打破了這個循環。如果沒有,我們會從explosionPrefab中新增爆炸並設置其在爆炸一段時間之後被毀滅。

explosion.png

我們需要做的最後一件事是在 Explosion 動畫的末尾添加一個召回(callback) 以呼叫 Explode 方法。你可以通過在動畫編輯器中打開“Explosion”,然後右鍵單擊最後一幀(frame)並選擇 Add Animation Event (添加動畫事件)。動畫事件功能將是 Explode 方法。

exlodeanimation.png

而且,你可以嘗試玩遊戲,讓炸彈爆炸。看看爆炸是否被正確連續製作 (停在牆壁和磚塊)。接下來我們要做的是允許爆炸破壞其他物體,比如玩家和炸彈。

bombermandropbomb

炸掉東西

爆炸應與玩家和炸彈相互作用。如果爆炸與玩家接觸,它應該殺死玩家。如果爆炸觸及炸彈,炸彈應該立即爆炸。

讓我們從玩家(player)的生命(life)開始製作,讓它死於炸彈。這將使用下面的 PlayerLife 腳本完成。該腳本將負責更新當前的生命數,同時也使得玩家在被損壞後很短的時間內就不會受到傷害。這樣可以防止玩家一次被多枚炸彈炸毀。

所以,LoseLife方法首先檢查玩家當前不是無敵的。如果它是脆弱的,它將減少目前的生命數量,並檢查這是否是最後的一條命。如果是這樣,它也會破壞玩家物件。在減少生命數量後,會使玩家無敵,並在無敵持續時間後調用“BecomeVulnerable”(易受傷害)方法。 “BecomeVulnerable” 的方法反過來又會使玩家再次變得脆弱。

loselife.png

現在我們要為“Explosion”做一個腳本,當與玩家相撞時,將呼叫 LoseLife 方法。該腳本將被稱為 ExplosionDamage,如下所示。我們將實施 OnTriggerEnter2D 方法,每當另一個物件與爆炸相撞時,它將被呼叫。當這種情況發生時,我們將通過其標籤檢查物件的類型(請記住正確設定 prefabs 標籤)。如果它是一個 “Character” 標籤,它將在 PlayerLife 腳本中呼叫 LoseLife方法。如果它是一個 “Bomb” 標籤,它將在 BombExplosion 腳本中呼叫 Explode 方法。這個Explode 方法與我們已經使用的一樣,所以我們不需要再做一個新的。

collider.png

然後,我們將這些腳本添加到它們各自的預製。

explosion_damage.png        player_life

現在,你可以嘗試玩和檢查爆炸是否與玩家和炸彈正確相互作用。不過,我們在遊戲中還是看不到現在的玩家人數。這是我們接下來要做的事情。

顯示玩家有幾條命

類似於我們如何在標題螢幕中顯示標題和文字,我們將建一個 Canvas(畫布)來顯示玩家的生命數。我們先建一個新的 Canvas(右鍵單擊層次結構Hierarchy,然後點 UI -> Canvas)並稱它為 HUDCanvas。這個 Canvas 的設定方式與 BackgroundCanvas 相同:

  • 將渲染模式(Render Mode)設為 Screen Space – Camera
  • 選擇 Main Camera 作為 Render Camera
  • 選擇排序圖層(Sorting Layer)作為遊戲(Game)
  • 將UI Scale Mode(縮放模式)設置為具有屏幕尺寸(Screen Size)的縮放

hud_canvas

現在我們要建一個物件,它將代表一網格來顯示玩家還有幾條命。我們可以通過建一個空物件作為畫布(Canvas)的子節點,然後添加一個網格佈局組(Grid Layout Group)組件來實現。然後,我們需要正確設定這個 Grid Layout Group,讓玩家按照我們想要的方式活命或死掉。

基本上,我們需要做的是將 Constraint 欄位更改為Fixed Row Count(固定行計數),且將 Constraint Count 更改為 1. 這將使網格在單行中顯示生命。此外,我們需要將單元格大小更改為 20×20。下圖顯示了 PlayerLivesGrid 物件。

player_lives_grid

現在我們需要建一個物件代表玩家的生命,並在生命的網格中進行管理。所以,讓我們建一個新的 Image 作為 HUDCanvas的一個子項,稱之為PlayerLifeImage並使其成為一個預製。在這個圖像中,我們只需要將 Source Image 設置為心精靈(heart sprite)。

player_life_image.png

現在,我們將改變 PlayerLife 腳本來管理玩家在網格中的生命。首先,我們需要添加兩個新的屬性:一個是玩家生命圖像預製,另一個為儲存所有玩家生命圖像的List。然後,在 Start 方法中,我們為每個玩家生命建一個PlayerLifeImage 物件。請注意,我們需要 PlayerLivesGrid 物件,以便我們可以創建圖像作為它的子項。建了每個圖像後,我們將其添加到 lifeImages列表中。

當玩家失去生命時,我們還需要更改 LoseLife 方法來銷毀 PlayerLifeImage。我們可以通過從 lifeImages 列表中檢索最後一個元素,摧毀它,然後從 List 中刪除它。

lifeimage.png

現在,我們已經可以玩遊戲,看到玩家的生命展示在螢幕上(下圖的三顆紅心)。在本教學中我們要做的最後一件事就是當玩家失去最後一條命時,添加一個Game Over的訊息。

battle_with_hud_canvas

Game Over 訊息

當玩家失去一切生命時,遊戲過程將再 HUD 畫布上顯示的文字。所以,讓我們開始在 HUD 畫布上創建文本(TEXT)。

首先,為了能輕鬆啟用和關閉文字,我們將把它們群組到一個物件中。所以,首先創建一個名為 GameOverPanel 的空物件。然後,我們將附加 StartGame 腳本。StartGame 腳本與我們在標題場景中使用的腳本是一樣的,我們將再次使用它,因為我們想在遊戲結束後重新啟動遊戲。

game_over_panel-1.png

現在我們添加兩個文本(UI-> Text)作為 GameOverPanel 的子項。第一個將被稱為 GameOverMessage,並將顯示文本 “Game Over!”(遊戲結束!)。第二個將被稱為RetryMessage,並將顯示文本 “Press any key to retry”(按任意鍵重試)。你可以將字體大小調為你喜歡的。

retry_message.png  game_over_message.png

另外,為了確保 HUDCanvas 將出現在其他的一切之上,你可以創建另一個名為 HUD 的 Sorting Layer (排序層),並將Canvas分配給它。

hud_sorting_layer

現在,我們不勾選GameOverPanel旁邊的框框讓其在關閉狀態。我們這樣做是因為我們希望 GameOverPanel 僅在玩家輸掉遊戲時才出現。 

disabled_game_over_panel.png

最後,我們更改 PlayerLife 腳本,在遊戲結束時顯示 GameOverPanel 。我們經由添加 GameOverPanel 作為腳本的屬性達成此事。然後,在 LoseLife 方法中,當目前的生命數等於 0 時,我們將啟動 GameOverPanel。

activatelife.png

現在,你可以嘗試玩遊戲並經歷死亡,看看遊戲結束訊息是否正確顯示。另外,檢查是否可以重新啟動遊戲。

battle_with_game_over

在此我們完成這遊戲的單個玩家的功能。在下一個教學中,我們將製作此遊戲的多個玩家的功能,在戰鬥中添加兩個玩家!

本文作者:

Renan Oliveira

Renan 是計算機科學碩士生和遊戲愛好者。他在遊戲開發方面的興趣在幾年前就開始上2D遊戲引擎課程,做出些小型的2D引擎和遊戲。他接著開始上 Zenva遊戲開發課程 的Javascript和Phaser。目前他正在製作自己的遊戲。 查看Renan Oliveira發表的所有分享文

本文由Zenva授權翻譯,原文: How to Create a Multiplayer Bomberman Game in Unity – Part 2

你也許會有興趣

python12 z2 z1

覺得這篇有用嗎? 歡迎分享! 

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

分類

遊戲開發, 未分類