Skip to content
第07回 ゲームの状態と終了条件

2 / 4 状態遷移の集約と終了条件の判定 ​

このステップの目的

状態変数の直接書き換えを避け、ChangeState()に遷移処理を集約して安全な画面切り替えを実装します。

状態変更を ChangeState() に集約する ​

各所でstate = State::GameOver;やstate = State::Playing;と直接書き換えると、次の問題が起きます。

ゲームオーバー時のBGM再生やクリア時のスコア保存など、状態が変わる際の処理を、各所のif文の後に重複して書く必要があります。
予期しない状態遷移が起きたときも、どこで状態が変わったのかを特定しにくくなります。

そこで、状態の変更はすべてChangeState()を通して行います。

Game.cppcpp
void Game::ChangeState(State nextState)
{
    state = nextState;
}

変更箇所を一つにまとめると、第09回で音声を追加するときも制御しやすくなります。この関数に、タイトルに入ったらタイトルBGM、ゲームオーバーに入ったらゲームオーバーSEを再生する処理を追加できます。

プレイ中の終了条件判定 ​

プレイ中の更新処理(UpdatePlaying)の末尾で、勝敗の終了条件を判定してChangeState()を呼び出します。

Game.cppcpp
void Game::UpdatePlaying(float deltaTime)
{
    timeLeft -= deltaTime;
    if (timeLeft < 0.0f)
        timeLeft = 0.0f;

    player.Update(input, deltaTime);
    playerShots.Update(deltaTime);
    enemies.Update(deltaTime);
    enemyShots.Update(deltaTime);

    player.TryShoot(input, playerShots);

    ResolveCollisions();

    if (!player.IsAlive())
    {
        ChangeState(State::GameOver);
        return;
    }

    if (score >= tuning::game::ClearScore || timeLeft <= 0.0f)
    {
        ChangeState(State::GameClear);
        return;
    }

    // 発射時点のプレイヤー位置を、すべての敵が狙う位置として共有する
    Vector2 playerPosition = player.GetHitbox().GetCenter();
    for (Enemy& enemy : enemies.GetAll())
    {
        enemy.TryShoot(enemyShots, playerPosition);
    }
}

判定順序によるゲームルールの確定 ​

HPが0かどうかを、クリア条件より先に判定する点が重要です。

同じフレームで、最後の弾が敵に当たって30点に達し、敵弾にも当たってHPが0になる相打ちが起きた場合、どちらを優先するかを決めます。
ゲームオーバー判定を先に行い、成立したらreturnで関数を抜けます。これで、クリア条件を満たしても自機が撃破されていればゲームオーバーになる、というルールになります。

チェックリスト
  • 状態変更がすべてChangeState()を経由して行われている
  • プレイヤーの!IsAlive()によってゲームオーバーへ遷移する
  • スコア条件または時間切れによってゲームクリアへ遷移する
  • ゲームオーバー判定がクリア判定より先に評価されている理由を説明できる