Come strutturare gli stati di gioco in un sistema basato su entità / componenti


11

Sto realizzando un gioco progettato con il paradigma entità-componente che utilizza i sistemi per comunicare tra i componenti, come spiegato qui . Ho raggiunto il punto nel mio sviluppo che ho bisogno di aggiungere stati di gioco (come pausa, gioco, inizio livello, inizio round, fine gioco, ecc.), Ma non sono sicuro di come farlo con il mio framework. Ho visto questo esempio di codice sugli stati di gioco a cui tutti sembrano fare riferimento, ma non penso che si adatti al mio framework. Sembra che ogni stato gestisca il proprio disegno e il proprio aggiornamento. Il mio framework ha un SystemManager che gestisce tutti gli aggiornamenti tramite i sistemi. Ad esempio, ecco la mia classe 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());
    }

}

Anche tutto l'aggiornamento nel mio gioco è guidato dagli eventi. Non ho un loop come il loro che aggiorna semplicemente tutto allo stesso tempo.

Mi piace il mio framework perché semplifica l'aggiunta di nuovi GameObjects, ma non presenta i problemi che alcuni progetti basati sui componenti incontrano quando comunicano tra i componenti. Odierei buttarlo solo per fare una pausa al lavoro. C'è un modo in cui posso aggiungere stati di gioco al mio gioco senza rimuovere il design del componente entità? L'esempio di stato del gioco si adatta davvero al mio framework e mi manca qualcosa?

EDIT: potrei non aver spiegato abbastanza bene il mio quadro. I miei componenti sono solo dati. Se stavo codificando in C ++, probabilmente sarebbero delle strutture. Ecco un esempio:

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

}

I miei componenti non comunicano tra loro. I sistemi gestiscono la comunicazione tra componenti. Anche i miei sistemi non comunicano tra loro. Hanno funzionalità separate e possono essere facilmente separate. Il MovementSystem non ha bisogno di sapere che cosa rende RenderingSystem per spostare correttamente gli oggetti di gioco; deve solo impostare i giusti valori sui componenti, in modo che quando RenderingSystem esegue il rendering degli oggetti di gioco, disponga di dati precisi.

Lo stato del gioco non potrebbe essere un sistema, poiché deve interagire con i sistemi anziché con i componenti. Non sta impostando i dati; sta determinando quali funzioni devono essere chiamate.

Un GameStateComponent non avrebbe senso perché tutti gli oggetti di gioco condividono uno stato di gioco. I componenti sono ciò che compone gli oggetti e ognuno è diverso per ciascun oggetto diverso. Ad esempio, gli oggetti di gioco non possono avere gli stessi limiti. Possono avere limiti sovrapposti, ma se condividono un BoundsComponent, sono davvero lo stesso oggetto. Spero che questa spiegazione renda il mio quadro meno confuso.

Risposte:


4

Devo ammettere che non ho letto il link che hai pubblicato. Dopo la modifica e dopo aver letto il link fornito, la mia posizione è cambiata. Quanto segue riflette questo.


Non so che devi preoccuparti degli stati di gioco in senso tradizionale. Considerando il tuo approccio allo sviluppo, ogni sistema è così specifico che, in effetti, sono la gestione dello stato del gioco.

In un sistema di entità, i componenti sono solo dati, giusto? Quindi è uno stato. Nella sua forma più semplice, è solo una bandiera. Se costruisci i tuoi stati in componenti e permetti ai tuoi sistemi di consumare i dati di quei componenti e reagire agli stati (flag) al loro interno, costruirai la gestione dello stato in ciascun sistema stesso.

Sembra che i sistemi di gestione come l'esempio di AppHub non si applichino molto bene al tuo paradigma di sviluppo. La creazione di un super-sistema che incapsula altri sistemi sembra vanificare lo scopo di separare la logica dai dati.

Questo potrebbe aiutarti a capire cosa intendo per non dover gestire esplicitamente gli stati di gioco:

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


Si prega di vedere la mia modifica. Scusa se stavo confondendo.
Eva,

Aggiornato per riflettere le nuove scoperte e le tue modifiche. Spero che qualcuno con più esperienza nella costruzione di sistemi di entità entrerà in azione, poiché questa non è un'area in cui ho molta esperienza.
Cypher,

Che ne dici di rimuovere e aggiungere sistemi quando cambia lo stato del gioco? Ad esempio, quando metti in pausa il gioco, forse il tuo MovementSystem o CollisionSystem non sono necessari, ma vuoi comunque che il tuo RenderSystem disegni elementi sullo schermo. I sistemi attivi potrebbero rappresentare uno stato di gioco?
argenkiwi,

0

Lo stato è un valore che si applica a un oggetto. Lo stato del gioco, come suggerisce il nome, sarebbe lo stato di un oggetto "Gioco". Quell'oggetto di gioco - o più probabilmente, un componente specifico su di esso - traccerebbe lo stato corrente e creerebbe o distruggerebbe qualsiasi oggetto necessario per facilitare lo stato corrente. Poiché i tuoi componenti sono solo dati, avrai bisogno di un nuovo sistema per gestirli, anche se potrebbe esserci solo un'istanza del componente associato.

È difficile commentare come implementare la pausa quando non è chiaro come implementare l'aggiornamento. Il processo che emette gli eventi di aggiornamento potrebbe scegliere di non farlo, se l'oggetto del gioco dice che il gioco è in pausa. Il modo in cui l'oggetto di gioco comunica al processo di aggiornamento dipende da te; forse la tua getRelevantObjectschiamata dovrebbe consentire al programma di aggiornamento di trovare l'oggetto Gioco, o viceversa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.