Comment structurer les états de jeu dans un système basé sur une entité / un composant

11

Je fais un jeu conçu avec le paradigme entité-composant qui utilise des systèmes pour communiquer entre les composants comme expliqué ici . J'ai atteint le point dans mon développement que j'ai besoin d'ajouter des états de jeu (tels que pause, jeu, début de niveau, début de ronde, fin de jeu, etc.), mais je ne sais pas comment le faire avec mon framework. J'ai regardé cet exemple de code sur les états de jeu auquel tout le monde semble faire référence, mais je ne pense pas qu'il correspond à mon cadre. Il semble que chaque État gère son propre dessin et sa mise à jour. Mon framework a un SystemManager qui gère toutes les mises à jour à l'aide de systèmes. Par exemple, voici ma 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());
    }

}

De plus, toute la mise à jour de mon jeu est événementielle. Je n'ai pas de boucle comme la leur qui met simplement tout à jour en même temps.

J'aime mon framework car il facilite l'ajout de nouveaux GameObjects, mais n'a pas les problèmes rencontrés par certaines conceptions basées sur les composants lors de la communication entre les composants. Je détesterais le jeter juste pour faire une pause au travail. Existe-t-il un moyen d'ajouter des états de jeu à mon jeu sans supprimer la conception des composants d'entité? L'exemple d'état du jeu correspond-il réellement à mon framework, et il me manque juste quelque chose?

EDIT: Je n'ai peut-être pas suffisamment expliqué mon cadre. Mes composants ne sont que des données. Si je codais en C ++, ce serait probablement des structures. En voici un exemple:

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

}

Mes composants ne communiquent pas entre eux. Les systèmes gèrent la communication entre composants. Mes systèmes ne communiquent pas non plus entre eux. Ils ont des fonctionnalités distinctes et peuvent facilement être séparés. Le MovementSystem n'a pas besoin de savoir ce que le RenderingSystem rend pour déplacer correctement les objets du jeu; il suffit de définir les bonnes valeurs sur les composants, de sorte que lorsque le RenderingSystem restitue les objets du jeu, il dispose de données précises.

L'état du jeu ne peut pas être un système, car il doit interagir avec les systèmes plutôt qu'avec les composants. Il ne s'agit pas de définir des données; il s'agit de déterminer quelles fonctions doivent être appelées.

Un GameStateComponent n'aurait aucun sens car tous les objets de jeu partagent un état de jeu. Les composants sont ce qui compose les objets et chacun est différent pour chaque objet différent. Par exemple, les objets du jeu ne peuvent pas avoir les mêmes limites. Ils peuvent avoir des limites qui se chevauchent, mais s'ils partagent un BoundsComponent, ils sont vraiment le même objet. Espérons que cette explication rend mon cadre moins confus.

Eva
la source

Réponses:

4

J'avoue que je n'ai pas lu le lien que vous avez publié. Après votre modification et lecture du lien fourni, ma position a changé. Ce qui suit reflète cela.


Je ne sais pas si vous devez vous soucier des états de jeu au sens traditionnel. Compte tenu de votre approche du développement, chaque système est si spécifique qu'ils, en effet, sont la gestion de l' état du jeu.

Dans un système d'entités, les composants ne sont que des données, non? Il en va de même pour un État. Dans sa forme la plus simple, ce n'est qu'un drapeau. Si vous intégrez vos états dans des composants et autorisez vos systèmes à consommer les données de ces composants et à réagir aux états (indicateurs) qu'ils contiennent, vous intégrerez votre gestion des états dans chaque système lui-même.

Il semble que les systèmes de gestion tels que l'exemple AppHub ne s'appliquent pas très bien à votre paradigme de développement. La création d'un super-système qui encapsule d'autres systèmes semble aller à l'encontre du but de séparer la logique des données.

Cela pourrait vous aider à comprendre ce que je veux dire par le fait de ne pas avoir à gérer explicitement les états de jeu:

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

Chiffrer
la source
Veuillez voir ma modification. Désolé si j'étais déroutant.
Eva
Mis à jour pour refléter les nouvelles découvertes et vos modifications. J'espère que quelqu'un ayant plus d'expérience dans la construction de systèmes d'entités fera son entrée, car ce n'est pas un domaine dans lequel j'ai beaucoup d'expérience.
Cypher
Qu'en est-il de la suppression et de l'ajout de systèmes lorsque l'état du jeu change? Par exemple, lorsque vous mettez le jeu en pause, il se peut que votre MovementSystem ou CollisionSystem ne soit pas nécessaire, mais vous souhaitez quand même que votre RenderSystem dessine des éléments à l'écran. Les systèmes actifs pourraient-ils représenter un état de jeu?
argenkiwi
0

State est une valeur qui s'applique à un objet. L'état du jeu, comme son nom l'indique, serait l'état d'un objet «Jeu». Cet objet de jeu - ou plus probablement, un composant spécifique dessus - suivrait l'état actuel et créerait ou détruirait tous les objets nécessaires pour faciliter l'état actuel. Étant donné que vos composants ne sont que des données, vous aurez besoin d'un nouveau système pour gérer cela, même s'il ne peut y avoir qu'une seule instance de son composant associé.

Il est difficile de commenter la mise en œuvre de la pause lorsque la mise en œuvre de la mise à jour n'est pas claire. Le processus qui émet des événements de mise à jour peut choisir de ne pas le faire, si l'objet du jeu indique que le jeu est en pause. La façon dont l'objet de jeu communique avec le processus de mise à jour dépend de vous; votre getRelevantObjectsappel devrait peut-être permettre au programme de mise à jour de trouver l'objet Game, ou vice versa.

Kylotan
la source