Menu
CoddyTech

状態に応じた切り替え

CoddyのUnityジャーニー「本格的なゲームを作る」セクションの一部。レッスン 15/60。

ゲームの各状態では、フレームごとに異なる処理を行います。状態フィールドに対するswitchを使うと、状態ごとに1つのcaseに処理をまとめられ、各フレームでは必ず1つのcaseだけが実行されます。状態の変更は1つのメソッドを通じて行うため、画面は常に状態と一致します。このボス戦には、導入、戦闘、勝利画面があります。

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になるため、1回呼び出すだけでそのパネルを表示し、ほかの2つを非表示にできます。タイマーのリセットなど、状態に入るときに行う処理もEnterに記述します。そうすれば、フレームごとではなく1回だけ実行されます。

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の値を更新します。

「プレイ」を押して、2回競争しましょう。その後、「確認」を押します。

自分で試してみよう

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プレイグラウンド