状態に応じた切り替え
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回だけ実行されます。
チャレンジ
簡単5秒間のタップ競争を作りましょう。
SetStateでは、新しい状態のパネルだけを表示します。Playingに入るときは、taps = 0、timeLeft = roundTime、Taps: 0を設定し、GameOverに入るときは、resultTextにTaps: 3を表示します。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プレイグラウンド