So strukturieren Sie Spielzustände in einem auf Entitäten / Komponenten basierenden System

11

Ich mache ein Spiel, das mit dem Entity-Component-Paradigma entworfen wurde und Systeme verwendet, um zwischen Komponenten zu kommunizieren, wie hier erläutert . Ich habe den Punkt in meiner Entwicklung erreicht, an dem ich Spielzustände hinzufügen muss (z. B. Pause, Spielen, Levelstart, Rundenstart, Spielende usw.), bin mir aber nicht sicher, wie ich das mit meinem Framework machen soll. Ich habe mir dieses Codebeispiel für Spielzustände angesehen, auf die sich jeder zu beziehen scheint, aber ich denke nicht, dass es zu meinem Framework passt. Es scheint, dass jeder Staat seine eigene Zeichnung und Aktualisierung handhabt. Mein Framework verfügt über einen SystemManager, der alle Aktualisierungen mithilfe von Systemen übernimmt. Hier ist zum Beispiel meine RenderingSystem-Klasse:

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());
    }

}

Außerdem sind alle Aktualisierungen in meinem Spiel ereignisgesteuert. Ich habe keine Schleife wie die ihre, die einfach alles gleichzeitig aktualisiert.

Ich mag mein Framework, weil es das Hinzufügen neuer GameObjects erleichtert, aber nicht die Probleme hat, auf die einige komponentenbasierte Designs bei der Kommunikation zwischen Komponenten stoßen. Ich würde es hassen, es zu schmeißen, nur um eine Pause zur Arbeit zu bekommen. Gibt es eine Möglichkeit, meinem Spiel Spielzustände hinzuzufügen, ohne das Design der Entitätskomponenten zu entfernen? Passt das Spielstatusbeispiel tatsächlich zu meinem Framework und mir fehlt nur etwas?

EDIT: Ich habe mein Framework möglicherweise nicht gut genug erklärt. Meine Komponenten sind nur Daten. Wenn ich in C ++ codieren würde, wären sie wahrscheinlich Strukturen. Hier ist ein Beispiel von einem:

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;
    }

}

Meine Komponenten kommunizieren nicht miteinander. Systeme übernehmen die Kommunikation zwischen Komponenten. Meine Systeme kommunizieren auch nicht miteinander. Sie haben separate Funktionen und können leicht getrennt gehalten werden. Das MovementSystem muss nicht wissen, was das RenderingSystem rendert, um die Spielobjekte korrekt zu verschieben. Es müssen nur die richtigen Werte für die Komponenten festgelegt werden, damit das RenderingSystem beim Rendern der Spielobjekte genaue Daten enthält.

Der Spielstatus kann kein System sein, da er eher mit den Systemen als mit den Komponenten interagieren muss. Es werden keine Daten festgelegt. Es bestimmt, welche Funktionen aufgerufen werden müssen.

Eine GameStateComponent wäre nicht sinnvoll, da alle Spielobjekte einen Spielstatus gemeinsam haben. Komponenten bilden Objekte und jedes ist für jedes Objekt anders. Beispielsweise können die Spielobjekte nicht dieselben Grenzen haben. Sie können überlappende Grenzen haben, aber wenn sie eine BoundsComponent gemeinsam nutzen, sind sie wirklich dasselbe Objekt. Hoffentlich macht diese Erklärung meinen Rahmen weniger verwirrend.

Eva
quelle

Antworten:

4

Ich gebe zu, dass ich den von Ihnen geposteten Link nicht gelesen habe. Nach Ihrer Bearbeitung und dem Lesen des bereitgestellten Links hat sich meine Position geändert. Das Folgende spiegelt dies wider.


Ich weiß nicht, dass Sie sich um Spielzustände im traditionellen Sinne sorgen müssen. Unter Berücksichtigung Ihren Ansatzes für die Entwicklung, jedes System ist so spezifisch , dass sie in der Tat sind State Management des Spiels.

In einem Entitätssystem sind die Komponenten nur Daten, oder? So ist ein Staat. In seiner einfachsten Form ist es nur eine Flagge. Wenn Sie Ihre Zustände in Komponenten einbauen und Ihren Systemen erlauben, die Daten dieser Komponenten zu nutzen und auf die darin enthaltenen Zustände (Flags) zu reagieren, bauen Sie Ihre Zustandsverwaltung in jedes System selbst ein.

Es scheint, dass Managementsysteme wie das AppHub-Beispiel nicht sehr gut auf Ihr Entwicklungsparadigma zutreffen. Das Erstellen eines Supersystems, das andere Systeme kapselt, scheint den Zweck der Trennung von Logik und Daten zu vereiteln.

Dies könnte Ihnen helfen zu verstehen, was ich damit meine, dass Sie nicht explizit mit Spielzuständen umgehen müssen:

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

Chiffre
quelle
Bitte sehen Sie meine Bearbeitung. Entschuldigung, wenn ich verwirrend war.
Eva
Aktualisiert, um neue Entdeckungen und Ihre Änderungen widerzuspiegeln. Hoffentlich mischt sich jemand mit mehr Erfahrung im Aufbau von Entitätssystemen ein, da dies kein Bereich ist, in dem ich viel Erfahrung habe.
Cypher
Was ist mit dem Entfernen und Hinzufügen von Systemen, wenn sich der Spielstatus ändert? Wenn Sie beispielsweise das Spiel pausieren, wird Ihr MovementSystem oder CollisionSystem möglicherweise nicht benötigt, aber Sie möchten dennoch, dass Ihr RenderSystem Inhalte auf dem Bildschirm zeichnet. Könnten die aktiven Systeme einen Spielzustand darstellen?
Argenkiwi
0

Status ist ein Wert, der für ein Objekt gilt. Der Spielstatus ist, wie der Name schon sagt, der Status eines "Spiel" -Objekts. Dieses Spielobjekt - oder wahrscheinlicher eine bestimmte Komponente darauf - würde den aktuellen Status verfolgen und alle Objekte erstellen oder zerstören, die zur Erleichterung des aktuellen Status erforderlich sind. Da es sich bei Ihren Komponenten nur um Daten handelt, benötigen Sie ein neues System, um dies zu handhaben, auch wenn möglicherweise immer nur eine Instanz der zugehörigen Komponente vorhanden ist.

Es ist schwer zu kommentieren, wie Sie eine Pause implementieren würden, wenn nicht klar ist, wie Sie die Aktualisierung implementieren. Der Prozess, der Aktualisierungsereignisse ausgibt, kann sich dafür entscheiden, dies nicht zu tun, wenn das Spielobjekt angibt, dass das Spiel angehalten wurde. Wie das Spielobjekt mit dem Aktualisierungsprozess kommuniziert, liegt bei Ihnen. Vielleicht sollte Ihr getRelevantObjectsAnruf dem Updater ermöglichen, das Spielobjekt zu finden, oder umgekehrt.

Kylotan
quelle