[Unity 6] 敵人死亡時用事件 (Event) 來計算數量

2025.04.10 / Unity 引擎
假設有一個情境,要計算遊戲中死亡的敵人數量,最芭樂的作法是在生命值 (HP) 歸零時呼叫 GameManager 的方法來增加計數,但這個會讓敵人的程式和 GameManager 被綁在一起,如果哪天 GameManager 壞掉,敵人的程式也會全部停止運作,當然這不是我們想要的,所以才要改成事件的寫法。本文會先寫一段芭樂程式,實作敵人生成到死亡計數的功能,再用事件的方式來改寫它。

建立程式邏輯

我們的目標是固定時間生成敵人,敵人會自動扣血,當血量歸零時死亡,並且要計算累計死亡的敵人數量。

本文使用先前介紹的 Unity 事件 (Event) C# 語法 的專案為基礎,再加上協程 (Coroutine) 和基礎程式邏輯來實作遊戲邏輯。

生成敵人與死亡計數

新增 GameManager 腳本,宣告 enemyPrefabdeathEnemyAmount 變數,來儲存敵人的預製物件 (Prefab) 和累計的死亡數量。

遊戲開始時,Unity 會自動呼叫 StartStart 會呼叫我們寫的 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);

執行遊戲,現在的功能效果和一開始寫的程式相同,但是我們用事件來分割 GameManagerEnemyController 的功能,讓前者專注在生成和計數,後者專注在敵人自己的邏輯,程式的意圖更單純,後續會更好維護。

範例專案

本文所示範的內容皆已上傳至 GitHub (enemy-death 分支):tedliou/unity-event-tutorial

參考資料

技術文件

相關文章

Ted Liou

雲科碩士在讀中,專注於 Unity C#、TouchDesigner 技術。
只要願意以超連結標註本文,歡迎轉載或用於教材製作!