Как структурировать игровые состояния в системе на основе сущностей / компонентов


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

}

Также все обновления в моей игре основаны на событиях. У меня нет такой петли, которая просто обновляет все одновременно.

Мне нравится мой фреймворк, потому что он позволяет легко добавлять новые GameObjects, но не имеет проблем, с которыми сталкиваются некоторые основанные на компонентах проекты при взаимодействии между компонентами. Я не хотел бы бросать это просто, чтобы заставить паузу работать. Есть ли способ, которым я могу добавить игровые состояния в свою игру, не удаляя дизайн сущности-компонента? Соответствует ли пример состояния игры моему фреймворку, а я что-то упустил?

РЕДАКТИРОВАТЬ: Я, возможно, не объяснил мою структуру достаточно хорошо. Мои компоненты просто данные. Если бы я программировал на 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 отображала игровые объекты, у нее были точные данные.

Состояние игры не может быть системой, потому что оно должно взаимодействовать с системами, а не с компонентами. Это не настройка данных; это определяет, какие функции должны быть вызваны.

GameStateComponent не имеет смысла, потому что все игровые объекты имеют одно игровое состояние. Компоненты - это то, что составляет объекты, и каждый из них отличается для каждого отдельного объекта. Например, игровые объекты не могут иметь одинаковые границы. Они могут иметь перекрывающиеся границы, но если они совместно используют компонент BoundsComponent, это действительно один и тот же объект. Надеюсь, это объяснение делает мою структуру менее запутанной.

Ответы:


4

Я признаю, что я не читал ссылку, которую вы разместили. После вашего редактирования и прочтения предоставленной ссылки моя позиция изменилась. Ниже это отражено.


Я не знаю, что вам нужно беспокоиться о состояниях игры в традиционном смысле. Принимая во внимание ваш подход к разработке, каждая система настолько специфична, что фактически является управлением состоянием игры.

В системе сущностей компоненты - это просто данные, верно? Таково состояние. В простейшем виде это просто флаг. Если вы встраиваете свои состояния в компоненты и позволяете своим системам использовать данные этих компонентов и реагировать на состояния (флаги) внутри них, вы будете встраивать управление состояниями в каждую систему.

Кажется, что системы управления, такие как пример AppHub, не очень хорошо подходят для вашей парадигмы разработки. Создание суперсистемы, которая инкапсулирует другие системы, похоже, лишает цели отделения логики от данных.

Это может помочь вам понять, что я имею в виду, не имея необходимости явно обрабатывать игровые состояния:

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


Пожалуйста, смотрите мое редактирование. Извините, если я запутался.
Ева

Обновлено, чтобы отразить новые открытия и ваши правки. Надеюсь, кто-то с большим опытом в создании систем сущностей примет участие, так как это не та область, в которой у меня есть большой опыт.
Cypher

Как насчет удаления и добавления систем при изменении состояния игры? Например, когда вы приостанавливаете игру, возможно, ваша MovementSystem или CollisionSystem не нужны, но вы все равно хотите, чтобы ваша RenderSystem рисовала материал на экране. Могут ли активные системы представлять игровое состояние?
argenkiwi

0

Состояние - это значение, которое применяется к объекту. Состояние игры, как следует из названия, будет состоянием объекта «Игра». Этот объект Game - или, более вероятно, конкретный компонент на нем - будет отслеживать текущее состояние и создавать или уничтожать любые объекты, необходимые для облегчения текущего состояния. Поскольку ваши компоненты - это просто данные, вам понадобится новая Система, чтобы справиться с этим, хотя может быть только один экземпляр связанного с ним компонента.

Трудно комментировать, как бы вы реализовали паузу, когда неясно, как вы реализуете обновление. Процесс, который генерирует события обновления, может решить не делать этого, если игровой объект говорит, что игра приостановлена. Как игровой объект взаимодействует с процессом обновления, зависит от вас; возможно, ваш getRelevantObjectsвызов должен позволить модулю обновления найти объект Game, или наоборот.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.