Menu
CoddyTech

根据状态切换

本课属于 Coddy Unity 学习旅程的“打造真正的游戏”单元。第 15 课,共 60 课。

游戏的每种状态每帧都会执行不同的工作。对状态字段使用 switch,把这些工作分别放在每种状态对应的 case 中,每帧只会运行一个 case。状态通过同一个方法进行切换,因此屏幕始终与状态一致。这场 Boss 战有开场、战斗和胜利画面:

public enum Phase { Intro, Fight, Won }

public class BossFight : MonoBehaviour
{
    public GameObject introPanel;
    public GameObject fightPanel;
    public GameObject winPanel;
    public int bossHp = 10;
    private Phase phase;
    private float timer = 3f;

    void Start()
    {
        Enter(Phase.Intro);
    }

    void Update()
    {
        switch (phase)
        {
            case Phase.Intro:
                timer -= Time.deltaTime;
                if (timer <= 0f) Enter(Phase.Fight);
                break;
            case Phase.Fight:
                if (bossHp <= 0) Enter(Phase.Won);
                break;
            case Phase.Won:
                break;
        }
    }

    void Enter(Phase next)
    {
        phase = next;
        introPanel.SetActive(next == Phase.Intro);
        fightPanel.SetActive(next == Phase.Fight);
        winPanel.SetActive(next == Phase.Won);
    }
}

每个 case 都以 break 结束,因为 C# 不允许某个 case 执行完后直接继续执行下一个 case。开场计时器结束时,Enter(Phase.Fight) 会切换阶段,但 Fight case 要到下一帧才会运行,因为这一帧已经选定了要执行的 case。如果依次使用多个独立的 if 代码块,同一帧就可能开始战斗并运行战斗代码。

Enter 是唯一会更改 phase 的地方。只有战斗面板对应的 next == Phase.Fight 才会得到 true,因此调用一次就能显示该面板并隐藏另外两个面板。进入某种状态时要执行的工作,例如重置计时器,也放在 Enter 中,这样只会运行一次,而不是每帧都运行。

challenge icon

挑战

简单

制作 5 秒点击竞速游戏。

  1. 在 SetState 中,只显示新状态对应的面板。进入 Playing 时,将 taps = 0、timeLeft = roundTime 和 Taps: 0;进入 GameOver 时,在 resultText 中显示 Taps: 3。
  2. 在 Update() 中,使用 switch (state):按空格键可让 Ready 进入 Playing,并让 GameOver 返回 Ready;在 Playing 状态下,每按一次空格键,就将点击次数计入 taps 和 tapsText,直到时间结束。

按“开始”,竞速两次。然后按“检查”。

亲手试试

using UnityEngine;
using TMPro;

public enum GameState { Ready, Playing, GameOver }

public class GameManager : MonoBehaviour
{
    public GameObject readyPanel;
    public GameObject playPanel;
    public GameObject gameOverPanel;
    public TMP_Text tapsText;
    public TMP_Text resultText;
    public float roundTime = 5f;
    public GameState state;
    private int taps;
    private float timeLeft;

    void Start()
    {
        SetState(GameState.Ready);
    }

    void Update()
    {
        // 根据 state 切换:
        // Ready:按 Space 开始一轮游戏
        // Playing:每按一次 Space 计一次点击;时间一到,游戏结束
        // GameOver:按 Space 返回 Ready
    }

    void SetState(GameState next)
    {
        state = next;
        // 只显示新状态对应的面板
        // 新一轮从 0 次点击和 roundTime 秒开始;结束时,resultText 显示点击次数
    }
}

打造真正的游戏中的所有课

自己练习: Unity 在线编辑器