エンティティ/コンポーネントベースのシステムでゲームの状態を構造化する方法


11

ここで説明するように、コンポーネント間の通信にシステムを使用するエンティティコンポーネントパラダイムで設計されたゲームを作成しています。開発の段階で、ゲームの状態(一時停止、再生、レベルスタート、ラウンドスタート、ゲームオーバーなど)を追加する必要がありますが、フレームワークでそれを行う方法がわかりません。私は誰もが参照していると思われるゲームの状態に関するこのコード例を見てきましたが、私のフレームワークに適合しないと思います。各州が独自の描画と更新を処理しているようです。私のフレームワークには、システムを使用してすべての更新を処理するSystemManagerがあります。たとえば、次は私のRenderingSystemクラスです。

public class RenderingSystem extends GameSystem {

    private GameView gameView_;

    /**
     * Constructor
     * Creates a new RenderingSystem.
     * @param gameManager The game manager. Used to get the game components.
     */
    public RenderingSystem(GameManager gameManager) {
        super(gameManager);
    }

    /**
     * Method: registerGameView
     * Registers gameView into the RenderingSystem.
     * @param gameView The game view registered.
     */
    public void registerGameView(GameView gameView) {
        gameView_ = gameView;
    }

    /**
     * Method: triggerRender
     * Adds a repaint call to the event queue for the dirty rectangle.
     */
    public void triggerRender() {
        Rectangle dirtyRect = new Rectangle();

        for (GameObject object : getRenderableObjects()) {
            GraphicsComponent graphicsComponent =
                    object.getComponent(GraphicsComponent.class);
            dirtyRect.add(graphicsComponent.getDirtyRect());
        }

        gameView_.repaint(dirtyRect);
    }

    /**
     * Method: renderGameView
     * Renders the game objects onto the game view.
     * @param g The graphics object that draws the game objects.
     */
    public void renderGameView(Graphics g) {
        for (GameObject object : getRenderableObjects()) {
            GraphicsComponent graphicsComponent =
                    object.getComponent(GraphicsComponent.class);
            if (!graphicsComponent.isVisible()) continue;

            GraphicsComponent.Shape shape = graphicsComponent.getShape();
            BoundsComponent boundsComponent =
                    object.getComponent(BoundsComponent.class);
            Rectangle bounds = boundsComponent.getBounds();

            g.setColor(graphicsComponent.getColor());

            if (shape == GraphicsComponent.Shape.RECTANGULAR) {
                g.fill3DRect(bounds.x, bounds.y, bounds.width, bounds.height,
                        true);
            } else if (shape == GraphicsComponent.Shape.CIRCULAR) {
                g.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
            }
        }
    }

    /**
     * Method: getRenderableObjects
     * @return The renderable game objects.
     */
    private HashSet<GameObject> getRenderableObjects() {
        return gameManager.getGameObjectManager().getRelevantObjects(
                getClass());
    }

}

また、私のゲームの更新はすべてイベント駆動型です。単純にすべてを同時に更新するようなループはありません。

フレームワークが気に入ったのは、新しいゲームオブジェクトを簡単に追加できるためですが、コンポーネントベースのデザインでコンポーネント間の通信時に発生する問題はありません。作業を一時停止するためだけに、それをチャックするのは嫌です。エンティティコンポーネントのデザインを削除せずにゲームにゲームステートを追加する方法はありますか?ゲームステートの例は実際に私のフレームワークに適合していますか?

編集: 私は私のフレームワークを十分に説明しなかったかもしれません。私のコンポーネントは単なるデータです。C ++でコーディングしている場合、おそらく構造体になります。以下はその例です。

public class BoundsComponent implements GameComponent {

    /**
     * The position of the game object.
     */
    private Point pos_;

    /**
     * The size of the game object.
     */
    private Dimension size_;

    /**
     * Constructor
     * Creates a new BoundsComponent for a game object with initial position
     * initialPos and initial size initialSize. The position and size combine
     * to make up the bounds.
     * @param initialPos The initial position of the game object.
     * @param initialSize The initial size of the game object.
     */
    public BoundsComponent(Point initialPos, Dimension initialSize) {
        pos_ = initialPos;
        size_ = initialSize;
    }

    /**
     * Method: getBounds
     * @return The bounds of the game object.
     */
    public Rectangle getBounds() {
        return new Rectangle(pos_, size_);
    }

    /**
     * Method: setPos
     * Sets the position of the game object to newPos.
     * @param newPos The value to which the position of the game object is
     * set.
     */
    public void setPos(Point newPos) {
        pos_ = newPos;
    }

}

コンポーネントが相互に通信しません。システムはコンポーネント間の通信を処理します。また、私のシステムは互いに通信しません。それらは別々の機能を持ち、簡単に別々に保つことができます。MovementSystemは、ゲームオブジェクトを正しく移動するために、RenderingSystemが何をレンダリングしているかを知る必要はありません。コンポーネントに適切な値を設定するだけで、RenderingSystemがゲームオブジェクトをレンダリングするときに正確なデータが得られます。

コンポーネントではなくシステムとやり取りする必要があるため、ゲームの状態をシステムにすることはできません。データの設定ではありません。呼び出す必要がある関数を決定します。

すべてのゲームオブジェクトが1つのゲーム状態を共有するため、GameStateComponentは意味がありません。コンポーネントはオブジェクトを構成するものであり、コンポーネントはオブジェクトごとに異なります。たとえば、ゲームオブジェクトは同じ境界を持つことはできません。それらは重複する境界を持つことができますが、BoundsComponentを共有する場合、それらは実際には同じオブジェクトです。うまくいけば、この説明によって私のフレームワークの混乱が少なくなります。

回答:


4

私はあなたが投稿したリンクを読んでいないことを認めます。あなたの編集と提供されたリンクを読んだ後、私の立場は変わった。以下はこれを反映しています。


伝統的な意味でのゲームの状態について心配する必要があることは知りません。開発へのアプローチを考えると、各システムは非常に具体的であるため、実際にゲームの状態管理になります。

エンティティシステムでは、コンポーネントは単なるデータですよね?状態です。最も単純な形式では、それは単なるフラグです。状態をコンポーネントに組み込み、システムがそれらのコンポーネントのデータを使用し、コンポーネント内の状態(フラグ)に反応できるようにすると、各システム自体に状態管理が組み込まれます。

AppHubの例などの管理システムは、開発パラダイムにはあまり適していないようです。他のシステムをカプセル化するスーパーシステムを作成すると、ロジックをデータから分離する目的が損なわれるようです。

これは、ゲームの状態を明示的に処理する必要がないことについての私の理解を理解するのに役立ちます。

http://paulgestwicki.blogspot.com/2012/03/components-and-systems-of-morgans-raid.html


私の編集を見てください。混乱していた場合は申し訳ありません。
エヴァ

新しい発見とあなたの編集を反映するように更新されました。これは私が多くの経験を持っていることの領域ではないとうまくいけば、実体のシステムを構築する上でより多くの経験を持った人は、中にチャイムます。
サイファー

ゲームの状態が変化したときにシステムを削除および追加するのはどうですか?たとえば、ゲームを一時停止する場合、MovementSystemやCollisionSystemは必要ないかもしれませんが、それでも、RenderSystemが画面上に描画する必要があります。アクティブなシステムはゲームの状態を表すことができますか?
argenkiwi 2014

0

状態は、オブジェクトに適用される値です。名前が示すように、ゲームの状態は「ゲーム」オブジェクトの状態になります。そのゲームオブジェクト、またはおそらくその上の特定のコンポーネントは、現在の状態を追跡し、現在の状態を促進するために必要なオブジェクトを作成または破棄します。コンポーネントは単なるデータなので、関連するコンポーネントのインスタンスが1つしかない場合でも、これを処理するには新しいシステムが必要です。

更新の実装方法が明確でない場合に、一時停止を実装する方法についてコメントするのは困難です。ゲームオブジェクトがゲームを一時停止していると言った場合、更新イベントを発行するプロセスは、そうしないことを選択できます。ゲームオブジェクトが更新プロセスと通信する方法はあなた次第です。おそらくあなたのgetRelevantObjects呼び出しは、アップデーターがゲームオブジェクトを見つけることを許可するべきです、またはその逆です。

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