Menu
CoddyTech

清空竞技场

本课属于 Coddy Unity 学习旅程的“Unity 游戏架构”单元。第 55 课,共 64 课。

标记为 static 的事件属于类,而不是某个对象。无论有多少敌人,Enemy.Died 都只有一个,因此生成器可以在任何敌人出现之前订阅该事件:Enemy.Died += OnEnemyDied;,每个敌人触发事件时都会将自身作为参数传入。用纯 C# 表达相同的思路:

public class Coin
{
    public static event Action<Coin> Picked;

    public void Pick()
    {
        Picked?.Invoke(this);
    }
}

public class Purse
{
    private int coins;

    public Purse()
    {
        Coin.Picked += OnPicked;   // 暂时不需要 Coin
    }

    void OnPicked(Coin coin)
    {
        coins++;
    }
}

实例事件通过对象访问,例如 hero.Died;静态事件则通过类名访问,例如 Coin.Picked。静态事件的生命周期比所有对象都长,因此要在 OnDisable 中取消订阅,否则被销毁的生成器仍会留在事件列表中。

challenge icon

挑战

中等

让每一波都等到竞技场中没有敌人为止。

  1. 在 Enemy 中,添加 public static event Action<Enemy> Died;,并在 Destroy(gameObject); 之前调用 Died?.Invoke(this);。
  2. 在 WaveSpawner 中统计 alive:每生成一个敌人就加 1,在一个由 OnEnable 添加到 Enemy.Died、并由 OnDisable 移除的方法中减 1。
  3. 一波敌人生成后,在 alive > 0 时等待。

按下“开始”并击败第 1 波敌人:2 秒后出现第 2 波。然后点击“检查”。

亲手试试

using System.Collections;
using UnityEngine;

public class WaveSpawner : MonoBehaviour
{
    [SerializeField] private WaveSet waveSet;
    [SerializeField] private Transform[] spawnPoints;

    public int Wave { get; private set; }

    void Start()
    {
        StartCoroutine(RunWaves());
    }

    IEnumerator RunWaves()
    {
        while (true)
        {
            foreach (Wave wave in waveSet.waves)
            {
                Wave++;
                Debug.Log("Wave " + Wave);
                for (int i = 0; i < wave.count; i++)
                {
                    Transform point = spawnPoints[i % spawnPoints.Length];
                    Instantiate(wave.enemy, point.position, Quaternion.identity);
                    yield return new WaitForSeconds(wave.spacing);
                }
                yield return new WaitForSeconds(waveSet.restBetweenWaves);
            }
        }
    }
}

Unity 游戏架构中的所有课

自己练习: Unity 在线编辑器