Як структурувати ігрові стани в системі на основі об'єкта / компонентів


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, але не має проблем, з якими стикаються дизайни на основі компонентів під час спілкування між компонентами. Мені б не хотілося це робити, щоб призупинити роботу. Чи можна додати стани гри до своєї гри, не знімаючи дизайн-компонент сутності? Чи дійсно приклад стану гри відповідає моїм рамкам, і я просто щось пропускаю?

EDIT: Я, можливо, недостатньо добре пояснив свої рамки. Мої компоненти - це лише дані. Якби я кодував 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

Стан - це значення, яке стосується об'єкта. Стан гри, як випливає з назви, було б станом об’єкта «Гра». Цей ігровий об’єкт - або, швидше за все, конкретний компонент на ньому - би відслідковував поточний стан та створював або знищував усі об'єкти, необхідні для полегшення поточного стану. Оскільки ваші компоненти - це лише дані, вам буде потрібна нова система для управління цим, хоча може існувати лише один примірник його асоційованого компонента.

Важко коментувати, як би ви реалізували паузу, коли не ясно, як ви реалізуєте оновлення. Процес, який випромінює події оновлення, може не робити цього, якщо ігровий об’єкт каже, що гра призупинена. Те, як ігровий об’єкт передає процес оновлення, залежить від вас; можливо, ваш getRelevantObjectsдзвінок повинен дозволити оновителю знайти об’єкт гри, або навпаки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.