Appearance
第08回 GameManagerとゲーム状態
1 / 5 状態遷移の仕様を決める
このステップの目的
ゲーム全体の状態を整理し、遷移図と遷移表からGameStateを定義します。
ゲーム全体の状態を管理する
第07回までに、PlayerもEnemyもダメージを受け、HPが0になると死亡するシステムが入りました。ですがこの時点ではまだゲームクリアやゲームオーバーは実装されていません。
ゲームには、複数のオブジェクトから届く情報をまとめ、ルールに従って結果を決める、より大きな管理マネージャーが必要です。今回はGameManagerを実装し、ゲーム全体の状態を管理します。
GameManagerはゲームの進行状態を表すGameStateを持ち、Enemyの撃破数とPlayerのHPから勝敗を決めます。
| 情報 | 発生元 | GameManagerの判断 |
|---|---|---|
| Enemyを1体倒した | Enemy | 撃破数を1増やす |
| 撃破数が目標へ達した | 撃破数 | ゲームクリアにする |
| PlayerのHPが0になった | DamageReceiver | ゲームオーバーにする |
GameManagerはゲームの進行状態を管理することに専念するクラスとします。Enemyが行う追跡やPlayerのHP計算といった細々とした処理には干渉しません。
ステートマシン
特定の状態(ステート)にいるときだけ特定の処理を許可する仕組みをステートマシン(State Machine、状態機械)と呼びます。ゲームで使われる様々なオブジェクトの状態を管理するのに適しており、敵キャラクターの制御やUI挙動の制御など、様々な目的で使われる重要な機構です。
今回のGameManagerもステートマシンとして実装し、ゲームの進行状態を管理します。
ステートマシンの構成要素
ステートマシンは以下の要素で構成されます。
- 状態:現在どの状態にあるかを表す
- 遷移条件:遷移を許可する条件
- 遷移時処理:状態が変わった瞬間に一度だけ行う処理
遷移条件が満たされたステートマシンは別の状態へ遷移します。例えばゲームキャラクターのステートマシンでは、HPが0になったら死亡する、死亡時に蘇生魔法をかけられたら生き返る、といった具合です。
ここで状態に応じて許可される遷移の条件を定めることで、ステートマシンの挙動を簡潔に表現できます。死亡時に攻撃を受けても二重三重に死亡することはない、生存中に蘇生魔法をかけられても生き返りはしない、といったルールをステートマシンの構成要素として定義できます。
また、状態から抜ける、あるいは別の状態へ入るときに遷移時処理を行うことで、切り替えに伴う特別な処理を実装できます。死亡時に死亡アニメーションを再生する、蘇生時にHPを回復する、といった処理が該当します。
このように、ステートマシンは状態、遷移条件と遷移、遷移時処理で構成されます。
第06回のEnemyStateとの比較
第06回のEnemyStateも、簡易ながらステートマシンの実装例です。1体のEnemyが待機、移動、攻撃、被弾、死亡のどれを行っているかを表しました。
今回のGameStateは、ゲーム全体が開始前、プレイ中、勝利、敗北のどこにいるかを表しています。
それぞれは個別のステートマシンで、独立した存在です。複数のステートマシンを組み合わせることで複雑なゲームの進行を実現するのがゲームプログラミングの基本となります。
遷移図と遷移表から仕様を決める
コードを書く前に、ステートマシンの仕様を遷移図と遷移表で整理します。
| 構成要素 | 意味 | 今回の例 |
|---|---|---|
| 状態 | 現在どの段階にいるか | Ready、Playing、GameClear、GameOver |
| 遷移 | ある状態から別の状態へ切り替わること | PlayingからGameClearへ切り替わる |
| 遷移条件 | 遷移を許可する条件 | 撃破数が目標以上になる |
| 遷移時処理 | 状態が変わった瞬間に一度行う処理 | UIへ通知する、時間進行を止める |
| 現在状態 | 条件 | 次の状態 | 遷移時処理 |
|---|---|---|---|
Ready | Start()が呼ばれる | Playing | 開始を通知する |
Playing | 撃破数が目標以上 | GameClear | 生成停止、結果通知、時間停止 |
Playing | Playerが死亡 | GameOver | 生成停止、結果通知、時間停止 |
図を準備しています…
今回、GameClearからPlayingへ直接戻る遷移は用意しません。再挑戦では、次回作成する処理でGame Scene自体を読み直します。終了条件の通知を受け取ると即座に終了状態へ遷移し、それ以降の終了通知は受け付けません。そのため、複数の終了条件が同じフレームに成立した場合は、先に通知された結果を採用します。
GameStateで状態の候補を定義する
Assets/Scripts/GameState.csを作成します。
GameState.cscs
public enum GameState
{
Ready,
Playing,
GameClear,
GameOver
}ReadyはGameManagerが生成されてからStart()が実行されるまでの開始前、Playingは勝敗判定を受け付ける状態です。残りの2つは終了状態です。
enum を活用する
列挙型 enumは、関連する定数(変更されない値)をグループ化してコードの可読性を高めるための値型です。デフォルトはint型で、0から順に整数値が割り当てられます。
通常のC#プログラミングで、0や1のような直接的な値で状態管理を行うことは基本的には行いません。値の変更に追従できず、コードの可読性も低下するためです。
enumは名前が与えられただけの単純な整数のように振舞いますが、スペルミスや不正な値の代入をコンパイルエラーとして検出できるという強力な利点があります。ステートマシンの状態のような、取り得る値が限られている場合の表現に非常に適しています。ぜひ活用してください。
チェックリスト
Ready、Playing、GameClear、GameOverの役割と、許可する遷移を説明できる。