Menu
CoddyTech

状態に応じた切り替え

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

ゲームの各状態は、フレームごとに異なる処理を行います。状態フィールドに対するswitchを使うと、状態ごとに1つのケースに処理をまとめられ、各フレームでは必ず1つのケースだけが実行されます。状態の変更は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);
    }
}

C#では、次のケースへ続けて実行されるケースはコンパイルできないため、各ケースの末尾にbreakを置きます。導入のタイマーが切れると、Enter(Phase.Fight)によってフェーズが変わりますが、このフレームではすでに実行するケースが決まっているため、Fightケースが実行されるのは次のフレームです。ifブロックを続けて個別に書いた場合、同じフレーム内に戦闘が始まり、戦闘のコードも実行されることがあります。

Enterだけがphaseを変更する場所です。next == Phase.Fightは戦闘パネルに対してのみtrueとなるため、1回の呼び出しでそのパネルを表示し、ほかの2つを非表示にします。タイマーのリセットなど、状態に入るときに行う処理もEnterに記述すると、毎フレームではなく1回だけ実行されます。

challenge icon

チャレンジ

簡単

連打レース:5秒間にSpaceキーを何回押せるでしょうか? GameManager には、GameState 列挙型(Ready、Playing、GameOver)、各状態用のパネルがあり、StartではSetState(GameState.Ready)を呼び出します。UpdateとSetStateを記述しましょう。

Updateでは、stateに応じて分岐します。

  • Ready:Spaceキーを押すとラウンドが始まります。このときの押下は連打回数に含めません。
  • Playing:Spaceキーを押すたびにtapsに1を加算し、tapsTextにTaps: 3のように表示します。roundTime秒(5秒)後にゲームが終了します。
  • GameOver:Spaceキーを押すとReadyに戻ります。

SetState(GameState next)はstateを設定し、新しい状態のパネルだけを表示します。Playingに入ると、連打回数を0にして、画面にTaps: 0と表示し、残り時間をroundTime秒にしてラウンドを開始します。GameOverに入ると、結果をresultTextにTaps: 3のように表示します。

Playを押して、2回レースをしてからCheckを押してください。

自分で試してみよう

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 にタップ数を表示する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

本格的なゲームを作るのすべてのレッスン