XNAメモ – ゲームの状態変更の実装方法1 (switch編)

Posted: 2012年1月17日 カテゴリー: プログラミングメモ, XNA, XNAメモ
タグ:, , , , , , , , , ,

今回はゲーム内の状態変化の実装の仕方についてメモります。

状態変化とは具体的な例を挙げれば:

 

オープニング → メニュー → ゲーム→ その他色々

 

と言う風にシーンを移動することです。

これに関しては実装方法が幾つかあり、1回で全部を書くのは時間がかかるので、今回はenumとswitch文を使用しての実装方法を書きます。なお、このメモには前に書いたメニュークラスと、同じ記事で説明した入力用のメソッドを使っています。今回乗せる全てのコードは、Game1クラス内に書かれています。

 

まず、状態(シーン)のタイプを表すenumを宣言します。

enum GameStates
{
Menu,
InGame,
Pause,
};

// 現在の状態を表す変数。最初はメニュー画面
GameStates state = GameStates.Menu;

次に、Update()メソッド内にGameStatesのenumを使用してのswitch文を書きます。これで各シーンごとに何を更新するかを決めています(例:stateの値がGameStates.Pauseの場合は、ポーズの部分だけを処理する)。Switch文が長くなると読みにくくなるので、各シーンの処理は個別のメソッドに分けています。

protected override void Update(GameTime gameTime)
{
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;

// 現在の状態によって呼ぶupdateメソッドを
// 変更する
switch (state)
{
case GameStates.Menu:
UpdateMenu(delta);
break;
case GameStates.InGame:
UpdateInGame(delta);
break;
case GameStates.Pause:
UpdatePause(delta);
break;
}

base.Update(gameTime);
}
 

各メソッドの処理は必要なものに合わせてください。メニュー画面は、前に作ったものをUpdateMenu()メソッドに移すことも出来ます。

private void UpdateMenu(float delta)
{
menu.Update(delta);
if (Input.IsPressed(Keys.Down))
{
// 下へ移動
menu.SelectNext();
}

if (Input.IsPressed(Keys.Up))
{
// 上へ移動
menu.SelectPrevious();
}

// メニューで選択された場合
if (Input.IsPressed(Keys.Enter))
{
int option = menu.SelectedNumber;

if (option == 0)
{
state = GameStates.InGame;
}
else if (option == 1)
{
// ...Optionが選択されたときの処理
}
else if (option == 2)
{
this.Exit();
}
}
}

private void UpdateInGame(float delta)
{
if (Input.IsPressed(Keys.Space))
{
// ポーズ画面へ移動
state = GameStates.Pause;
}
else if (Input.IsPressed(Keys.Enter))
{
// メニュー画面へ移動
state = GameStates.Menu;
}
}

private void UpdatePause(float delta)
{
if (Input.IsPressed(Keys.Space))
{
// ゲーム画面へ戻る
state = GameStates.InGame;
}
}
 

各メソッド内では、入力によってstate変数を変えることで違うシーンに移動しています。

後は、描画処理です。描画もUpdate()メソッドと同じ様に書くことで実装できます。

protected override void Draw(GameTime gameTime)

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();

switch (state)
{
case GameStates.Menu:
DrawMenu();
break;
case GameStates.InGame:
DrawInGame();
break;
case GameStates.Pause:
DrawPause();
break;
}

spriteBatch.End();
base.Draw(gameTime);
}
 

Draw()メソッドもUpdate()メソッド同様シーンごとにメソッドを分けています。ちなみに、このサンプルには2種類のSpriteFontを使用しています。

private void DrawMenu()
{
menu.Draw(spriteBatch, font);
spriteBatch.DrawString(largeFont, "Menu Screen", new Vector2(300, 20), Color.Silver);
}

private void DrawInGame()
{
spriteBatch.DrawString(largeFont, "In Game", new Vector2(300, 20), Color.Silver);
spriteBatch.DrawString(font, "Press Space to Pause", new Vector2(300, 300), Color.Silver);
spriteBatch.DrawString(font, "Press Enter to return to Menu", new Vector2(300, 340), Color.Silver);
}

private void DrawPause()
{
spriteBatch.DrawString(font, "Pause Screen", new Vector2(300, 20), Color.Silver);
spriteBatch.DrawString(font, "Press Space to resume", new Vector2(300, 300), Color.Silver);
}
 

以上です。実装後はこんな感じになります:

 

この方法はゲームのシーン以降だけでなく、様々なところで使えます。ですが、ゲームのシーン用となると処理が多くなり、結果的にGame1が巨大化したり、作業分担が面倒になるので、個人的にはオブジェクト指向を使った状態変化を実装することをオススメします。それに関しては、多分次回メモります。

コメント
  1. […] XNAメモ – ゲームの状態変更の実装方法1 (switch編) […]

    • Sol より:

      大変参考にさせていただいております。

      それで、少々困ったことが・・・

      上記のコードを書き終わりビルドすると・・・

      名前”input’は現在のコンテキスト内に存在しません。

      っとなります。

      using Microsoft.Xna.Framework.Input;

      は、いれてあるのにどうしてでしょうか?

      • K1 より:

        その部分に関しての説明を入れるのを忘れてました・・・
        そこは入力処理の部分を省くために、Inputと言う名の入力用クラスを使用しているだけです。

        なので、その部分は自分の好きなように入力処理を置き換えてください。

  2. araki より:

    大変参考にさせていただいております。
    今回の記事を参考に状態遷移にチャレンジしてみたのですが、なにぶん初心者なもので、どこに何を記述すればいいのかよく分からずやっているのでうまくいきません><
    もしよろしかったら、今回の記事のソースコード全文をお教え願いないでしょうか?
    よろしくお願いします。

    • K1 より:

      >>arakiさん
      申し訳ございませんが、ソースコードの全載せや、プロジェクト全体の配布は可能な限り避けているので、今回は配布できません。

      ただ、記事は可能な限り改善したいので、どこら辺が解り難いのかをなどをお教えくだされば、編集する時と、他の方が同じ質問がある時の参考になるので、良ければコメントをください。

      補足ですが、今回のサンプルはほぼ全文Game1クラス内に書いており、省略しているのは別のメモで紹介している入力関係と、メニューの部分だけなので、他の記事と合わせればフォントの読み込みと、メニューの初期化以外は全文載せと同じになります。

      • araki より:

        返信ありがとうございます。
        他の記事というのはどれを参考にすればいいのでしょうか?
        お手数かけて大変申し訳ありません><

      • K1 より:

        入力関係( Input.IsPressed() メソッド等) は好きな入力関係に置き換えればよくて、
        メニュー関連は XNA メモの 「メニューの作り方」 をご参照ください。 

  3. araki より:

    各メソッドの処理は必要なものに合わせてください。メニュー画面は、前に作ったものをUpdateMenu()メソッドに移すことも出来ます。

    private void UpdateMenu(float delta)
    {
    menu.Update(delta);
    if (Input.IsPressed(Keys.Down))
    {
    // 下へ移動
    menu.SelectNext();
    }

    if (Input.IsPressed(Keys.Up))
    {
    // 上へ移動
    menu.SelectPrevious();
    }

    // メニューで選択された場合
    if (Input.IsPressed(Keys.Enter))
    {
    int option = menu.SelectedNumber;

    if (option == 0)
    {
    state = GameStates.InGame;
    }
    else if (option == 1)
    {
    // …Optionが選択されたときの処理
    }
    else if (option == 2)
    {
    this.Exit();
    }
    }
    }

    private void UpdateInGame(float delta)
    {
    if (Input.IsPressed(Keys.Space))
    {
    // ポーズ画面へ移動
    state = GameStates.Pause;
    }
    else if (Input.IsPressed(Keys.Enter))
    {
    // メニュー画面へ移動
    state = GameStates.Menu;
    }
    }

    private void UpdatePause(float delta)
    {
    if (Input.IsPressed(Keys.Space))
    {
    // ゲーム画面へ戻る
    state = GameStates.InGame;
    }
    }

    この文はどこに記述すればよいのでしょうか?

  4. araki より:

    Draw()メソッドもUpdate()メソッド同様シーンごとにメソッドを分けています。ちなみに、このサンプルには2種類のSpriteFontを使用しています。

    private void DrawMenu()
    {
    menu.Draw(spriteBatch, font);
    spriteBatch.DrawString(largeFont, “Menu Screen”, new Vector2(300, 20), Color.Silver);
    }

    private void DrawInGame()
    {
    spriteBatch.DrawString(largeFont, “In Game”, new Vector2(300, 20), Color.Silver);
    spriteBatch.DrawString(font, “Press Space to Pause”, new Vector2(300, 300), Color.Silver);
    spriteBatch.DrawString(font, “Press Enter to return to Menu”, new Vector2(300, 340), Color.Silver);
    }

    private void DrawPause()
    {
    spriteBatch.DrawString(font, “Pause Screen”, new Vector2(300, 20), Color.Silver);
    spriteBatch.DrawString(font, “Press Space to resume”, new Vector2(300, 300), Color.Silver);
    }

    この文もどこに記述するのでしょうか?

    • K1 より:

      上記にもありますが、全ての文は、Game1クラス内にあります。
      質問されたどちらの処理も、その一つ前の説明文で紹介されているので、そちらをご参照ください。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中