建立程式邏輯
我們的目標是固定時間生成敵人,敵人會自動扣血,當血量歸零時死亡,並且要計算累計死亡的敵人數量。
本文使用先前介紹的 Unity 事件 (Event) C# 語法 的專案為基礎,再加上協程 (Coroutine) 和基礎程式邏輯來實作遊戲邏輯。
生成敵人與死亡計數
新增 GameManager
腳本,宣告 enemyPrefab
和 deathEnemyAmount
變數,來儲存敵人的預製物件 (Prefab) 和累計的死亡數量。
遊戲開始時,Unity 會自動呼叫 Start
,Start
會呼叫我們寫的 SpawnEnemy
協程,讓遊戲每 6 秒會生成一個敵人。
AddDeathAmount
方法則是讓 deathEnemyAmount
增加 1。
1using UnityEngine;
2using System.Collections;
3
4public class GameManager : MonoBehaviour
5{
6 public GameObject enemyPrefab;
7 public int deathEnemyAmount = 0;
8
9 private void Start()
10 {
11 StartCoroutine(SpawnEnemy());
12 }
13
14 private IEnumerator SpawnEnemy()
15 {
16 while (true)
17 {
18 yield return new WaitForSeconds(6);
19
20 Instantiate(enemyPrefab, Vector3.zero, Quaternion.identity);
21 Debug.Log("Spawn an Enemy");
22 }
23 }
24
25 public void AddDeathAmount()
26 {
27 deathEnemyAmount += 1;
28 Debug.Log("Death Enemy Amount: " + deathEnemyAmount);
29 }
30}
敵人扣血與死亡摧毀
新增 EnemyController
腳本,宣告 hp
變數,來計算敵人的生命值。
遊戲開始時,Start
會啟動 Hurt
協程,每秒減低 20 點的 hp
。
當 hp
等於或低於 0 時,程式會找到場景上的 GameManager
,呼叫 AddDeathAmount
方法,並自我摧毀。
1using UnityEngine;
2using System.Collections;
3
4public class EnemyController : MonoBehaviour
5{
6 public int hp = 100;
7
8 private void Start()
9 {
10 StartCoroutine(Hurt());
11 }
12
13 private IEnumerator Hurt()
14 {
15 while (true)
16 {
17 yield return new WaitForSeconds(1);
18
19 hp -= 20;
20
21 if (hp <= 0)
22 {
23 FindAnyObjectByType<GameManager>().AddDeathAmount();
24 Destroy(gameObject);
25 }
26 }
27 }
28}
接下來自行建立 Sphere,掛上 EnemyController
腳本,並將它 製作成預製物件。
GameManager
則放在場景上的空物件中,並將 Sphere 預製物件拖曳到 enemyPrefab
欄位。
觀察程式碼可以發現,EnemyController
直接呼叫了 GameManager
內的方法,如果現在 GameManager
壞了,又或者是 AddDeathAmount
要改功能或改名稱,會導致需要回來修改 EnemyController
的程式。
敵人的程式只要關心敵人自己的邏輯就好,最好不要在敵人的程式中動到其他功能。
為了解決這個問題,我們可以改成事件的寫法。
改成事件寫法
建立並觸發敵人死亡事件
我們要在敵人身上宣告一個 onDeath 事件,當敵人死亡時會觸發該事件。
首先,在 EnemyController
中引用事件的命名空間。
1using UnityEngine.Events;
接下來,用 UnityEvent
宣告一個公開的 onDeath
事件。
1public UnityEvent onDeath;
在判斷 hp
是否歸零的邏輯中,刪除 FindAnyObjectByType<GameManager>().AddDeathAmount();
,替換成觸發 onDeath
的程式。
1onDeath.Invoke();
現在,敵人只會在死亡時觸發自己身上的死亡事件,不會呼叫到其它與它無關的程式。
在生成敵人時監聽死亡事件
GameManager
的功能是生成敵人,我們要在敵人被生成時,同時監聽它的死亡事件,當它死亡時觸發 AddDeathAmount
方法。
修改第 20 行的程式,在敵人生成時監聽 onDeath
事件。
1var enemy = Instantiate(enemyPrefab, Vector3.zero, Quaternion.identity);
2enemy.GetComponent<EnemyController>().onDeath.AddListener(AddDeathAmount);
執行遊戲,現在的功能效果和一開始寫的程式相同,但是我們用事件來分割 GameManager
和 EnemyController
的功能,讓前者專注在生成和計數,後者專注在敵人自己的邏輯,程式的意圖更單純,後續會更好維護。
範例專案
本文所示範的內容皆已上傳至 GitHub (enemy-death 分支):tedliou/unity-event-tutorial