Cómo estructurar estados de juego en un sistema basado en entidad / componente


11

Estoy haciendo un juego diseñado con el paradigma de entidad-componente que usa sistemas para comunicarse entre componentes como se explicó aquí . Llegué al punto en mi desarrollo de que necesito agregar estados de juego (como pausa, juego, inicio de nivel, inicio de ronda, juego terminado, etc.), pero no estoy seguro de cómo hacerlo con mi marco. He visto este ejemplo de código en los estados de juego a los que todos parecen hacer referencia, pero no creo que se ajuste a mi marco. Parece que cada estado maneja su propio dibujo y actualización. Mi marco tiene un SystemManager que maneja todas las actualizaciones usando sistemas. Por ejemplo, aquí está mi clase 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());
    }

}

Además, todas las actualizaciones en mi juego están basadas en eventos. No tengo un ciclo como el de ellos que simplemente actualiza todo al mismo tiempo.

Me gusta mi marco porque hace que sea fácil agregar nuevos GameObjects, pero no tiene los problemas que encuentran algunos diseños basados ​​en componentes cuando se comunican entre componentes. Odiaría tirarlo solo para hacer una pausa en el trabajo. ¿Hay alguna manera de agregar estados de juego a mi juego sin eliminar el diseño del componente de entidad? ¿El ejemplo del estado del juego realmente se ajusta a mi marco y me falta algo?

EDITAR: Podría no haber explicado mi marco lo suficientemente bien. Mis componentes son solo datos. Si estuviera codificando en C ++, probablemente serían estructuras. Aquí hay un ejemplo de uno:

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

}

Mis componentes no se comunican entre sí. Los sistemas manejan la comunicación entre componentes. Mis sistemas tampoco se comunican entre sí. Tienen una funcionalidad separada y se pueden mantener fácilmente separadas. El MovementSystem no necesita saber qué renderiza el RenderingSystem para mover los objetos del juego correctamente; solo necesita establecer los valores correctos en los componentes, de modo que cuando RenderingSystem renderice los objetos del juego, tenga datos precisos.

El estado del juego no podría ser un sistema, ya que necesita interactuar con los sistemas en lugar de los componentes. No está estableciendo datos; determina qué funciones deben llamarse.

Un GameStateComponent no tendría sentido porque todos los objetos del juego comparten un estado de juego. Los componentes son los que componen los objetos y cada uno es diferente para cada objeto diferente. Por ejemplo, los objetos del juego no pueden tener los mismos límites. Pueden tener límites superpuestos, pero si comparten un BoundsComponent, son realmente el mismo objeto. Con suerte, esta explicación hace que mi marco sea menos confuso.

Respuestas:


4

Admito que no leí el enlace que publicaste. Después de su edición, y leyendo el enlace provisto, mi posición ha cambiado. Lo siguiente refleja esto.


No sé si debes preocuparte por los estados del juego en el sentido tradicional. Teniendo en cuenta su enfoque de desarrollo, cada sistema es tan específico que, en efecto, son la gestión del estado del juego.

En un sistema de entidad, los componentes son solo datos, ¿verdad? Entonces es un estado. En su forma más simple, es solo una bandera. Si construye sus estados en componentes y permite que sus sistemas consuman los datos de esos componentes y reaccionen a los estados (indicadores) dentro de ellos, estará construyendo su gestión de estado en cada sistema.

Parece que los sistemas de gestión como el ejemplo de AppHub no se aplican muy bien a su paradigma de desarrollo. La creación de un súper sistema que encapsula otros sistemas parece anular el propósito de separar la lógica de los datos.

Esto podría ayudarlo a comprender lo que quiero decir sobre no tener que manejar explícitamente los estados del juego:

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


Por favor vea mi edición. Lo siento si era confuso.
Eva

Actualizado para reflejar nuevos descubrimientos y sus ediciones. Con suerte alguien con más experiencia en la construcción de sistemas entidad se interrumpiría, ya que esto no es un área que no tengo mucha experiencia en.
Cypher

¿Qué pasa con la eliminación y la adición de sistemas cuando cambia el estado del juego? Por ejemplo, cuando haces una pausa en el juego, tal vez no se necesitan tus MotionSystem o CollisionSystem, pero aún así quieres que tu RenderSystem dibuje cosas en la pantalla. ¿Podrían los sistemas activos representar un estado de juego?
argenkiwi

0

El estado es un valor que se aplica a un objeto. El estado del juego, como su nombre indica, sería el estado de un objeto 'Juego'. Ese objeto del juego, o más probablemente, un componente específico en él, rastrearía el estado actual y crearía o destruiría los objetos necesarios para facilitar el estado actual. Dado que sus componentes son solo datos, necesitará un nuevo sistema para manejar esto, aunque solo haya una instancia de su componente asociado.

Es difícil comentar cómo implementaría la pausa cuando no está claro cómo implementa la actualización. El proceso que emite eventos de actualización podría elegir no hacerlo, si el objeto del juego dice que el juego está en pausa. La forma en que el objeto del juego se comunica con el proceso de actualización depende de usted; quizás su getRelevantObjectsllamada debería permitir que el actualizador encuentre el objeto Juego, o viceversa.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.