ゲームの状態管理(ゲーム、メニュー、タイトル画面など)


11

基本的に、これまでに作成したすべてのゲームで、「current_state」のような変数が常にあります。これには、「game」、「titlescreen」、「gameoverscreen」などがあります。

そして、私のUpdate関数には、巨大なものがあります:

if current_state == "game" 
  game stuf
  ...
else if current_state == "titlescreen"
  ...

しかし、私はこれが専門的できれいな状態の扱い方だとは思いません。これをより良い方法で行うためのアイデアはありますか?それともこれが標準的な方法ですか?


どの言語、フレームワークなどを使用していますか?
Petr Abdulin 2012

通常はLua + LOVEです。また、フレームワークによってこれを処理する方法が異なることも発見しました。SFMLは非常に素晴らしいScreenクラスを持っているようです。
David Gomes、2012

1
ステートマシンを調べましたか?
ダーカラ

1
右上の検索バーでゲームの状態を探すこともできます。結果が出るはずです。
TravisG 2012

Darcaraに2番目でなければならない-これは、ステートマシンの使用目的とまったく同じです。
balajeerc 2012

回答:


14

画面について話しているので、そのロジックをすべて別の画面に分離するのが最善だと思います。私が通常行うこと:

screenというインターフェースを定義し、複数の画面でそれを実装します。LoadingScreen、MainMenuScreen、GameScreen、GameOverScreen、HighScoreScreenなど。ゲームでは、現在の画面を保持する変数を配置します。ループごとに、screen.update()を呼び出し、現在の画面をレンダリングします。これにより、現在の画面で状態が定義されているため、「この状態でそれを行う場合」に多くのことを節約できます。

これにより、ロジックが非常に適切に分離されます。

コード例:

### Screen interface ###
public interface Screen {

    public void show();

    public void update(float delta);

    public void render(float delta);

    public void hide ();
}

### An implementation of screen ###
public class MainMenuScreen implements Screen {

    private Game game;

    public MainMenuScreen(Game game) {
        this.game = game;
    }

    public void show() {
        // init stuff
    }

    public void update(float delta) {
        // react to clicks, update animations etc.
        if (buttonwasclicked) {
            game.setScreen(new GameScreen(game)); // change the screen
        }
    }

    public void render(float delta) {
        // draw everything
    }

    public void hide() {
        // release all resources, as the screen is being hidden
    }
}

### Game, drawing the appropriate screen ###
public class Game {

    public Screen screen;

    public void update() {
        screen.update(getDeltaTime);
        screen.render();
    }

    public void setScreen(Screen screen) {
        this.screen.hide();

        this.screen = screen;
        this.screen.show();
    }
}

または、ゲームの設定によっては、ゲームとして無限ループが発生する場合があります。

while(true) {
    calculatetimesincelastframe()
    screen.update(time);
    screen.render(time);
}

5

すでにMiddleclassを使用している場合は、それに対応するためにStatefullと呼ばれる優れた状態マシンライブラリがあります。それは使いやすく、マツマンが提案したのと同じアイデアを捨てます。


2

あなたの場合はcurrent_state、変数が文字列である、これはLuaのでは本当に簡単です:

game_states = {}
function game_states.game()
    -- game stuff
end
function game_states.titlescreen()
    -- title screen stuff
end

-- then, inside the Update function:
game_states[current_state]()

1

私がやっていることは大体次のとおりです:

私は有向非循環グラフのデータ構造を持っています。これは本質的に、お互いを指すノードの集まりです。各ノードはゲームシステムを表します。たとえば、UI、世界、入力、レンダリング。そして、各ノードはその前後にある他のノードを指しています。すべてのノードが配置されたら、単純なリストにフラット化するのは簡単です。このDAGのセットアップは、ゲームの起動時に最初に行うことです。新しいシステムを追加したいときはいつでも、AIと言ったら、そのコードを書いて、それが何に依存し、何に依存すべきかをゲームに伝えることができます。

私のメインゲームループはその後に続き、各システムを順番に実行します。最初の入力が処理され、次に世界が更新され、次に他のものが処理されます... UIは終わりに近づいており、レンダリングは最後です。ゲームが最初に開始するとき、世界も物理もAIもないため、これらのステップは基本的にスキップされ、タイトル画面のみが表示されます。適切なゲームを開始すると、UIはワールドシステムにメッセージを送信してオンにします。UIはそれ自体を処理します。ゲームの状態の管理とは、さまざまなシステムのオンとオフを切り替えることを意味します。各システムには、他のすべてのシステムからほぼ独立して処理される独自の状態情報のセットがあります(これは完全にではありません)実際、多くのシステムは同じデータセットに作用します。たとえば、UIシステムは、たとえば世界からデータを取得して、たとえば情報を表示します。AIシステムは、世界中のエンティティを見てメッセージを送信する必要もあります)。


この答えは別の質問への良い答えです。
Matsemann 2012

どうして?彼はさまざまなゲームの状態を設定する方法を尋ねました。私の解決策は、現在のように状態マシンを使用するのではなく、ビットを状態マシンではなくDAGであるさまざまなシステムに分割することです。
Alex Ames

1

Lua + Love2dで私の州を整理する方法は次のとおりです。長いif / thenステートメントを回避します。

まず、update(dt)メソッドとrender()メソッドを含む基本クラスを作成します。onKeyDown(key)などのイベント処理メソッドを指定することもできます。このクラスをステージと呼びますが、メソッドを実装するオブジェクトはすべて機能します。次に、ゲームの状態ごとにそのクラスのインスタンスを作成し、必要なメソッドを実装します。次に、状態の名前と状態のインスタンスを含むキー/値テーブルを作成します。次に、特定の条件が満たされたときに状態が変更できるように、グローバルスコープでcurrentStateを追跡します。

states = {}
states["title"] = title   -- Where title implements Stage class.
states["game"] = game     -- You could create the instance of 'game' lazily too.
currentState = "title"

function love.update(dt)
    if states[currentState] ~= nil then
       states[currentState]:update(dt) 
    end
end

-1

まあ、きれいではありませんが、この方法で状態を処理することは問題ありません、IMO。次のように、各状態の関数を使用して、よりクリーンにすることができます。

if current_state == "game" 
  game()
else if current_state == "titlescreen"
  titlescreen()

または他の何かがこのアプローチであなたを悩ませています(つまり、Updateメソッドが非常に長いことを除いて)?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.