Что не так с архитектурой рисования и обновления игрового объекта? - PullRequest
17 голосов
/ 08 июня 2010

Каковы причины за и против прорисовки и обновления игрового объекта?Например, если у вас есть игра, в которой у игрока есть позиция на экране, почему бы не иметь всеобъемлющий класс:

public class Player {
    private int x, y, xVelocity, yVelocity;
    private Sprite s;
    //...

    public Player() {
        // load the sprite here, somehow?
    }

    public void draw(CustomGraphicsClass g) {
        g.draw(s, x, y);
    }

    public void update(long timeElapsed) {
        x += (xVelocity * timeElapsed);
        y += (yVelocity * timeElapsed);
    }
}

Что не так с этим дизайном?Каковы недостатки или проблемы?Как бы вы лучше написали что-то подобное или лучше разработали этот тип вещей в игре?

Кроме того, в некоторой степени, как бы вы реализовали загрузку этого изображения Sprite?

И, кроме того, кактогда вы бы реализовали коллизию между двумя Player с?

(вероятно, я должен разделить эти дополнительные два вопроса на новые вопросы, а?)

Ответы [ 6 ]

18 голосов
/ 09 июня 2010

Он объединяет весь ваш рендеринг и логический код, когда они имеют мало общего, кроме концептуально привязанного к одной и той же «сущности». По мере того, как ваш класс становится больше, вы можете оказаться с огромным монолитным Player, который нужно поддерживать. Разделение по границам доменов (рендеринг, ИИ) делает его более управляемым без необходимости много сдаваться, поскольку эти домены не имеют большого перекрытия.

Помимо удобства обслуживания, есть и другие соображения:

  1. Если вы хотите обрабатывать рендеринг и ИИ в разных потоках, смешивание их состояния в одном и том же классе просто напрашивается на неприятные проблемы с многопоточностью.

  2. Если вы используете такой язык, как C ++, такие высокосвязанные классы могут убить время компиляции.

  3. В зависимости от того, как ваш код и объекты размещены в памяти, разбиение объектов на отдельные компоненты для каждого домена может обеспечить лучшую согласованность кэша и гораздо лучшую производительность.

Вот больше информации , если вам интересно.

3 голосов
/ 08 июня 2010

Предположим, что каждый раз, когда ваш объект (т.е. игрок) обновляется, он должен

1) перерисовать себя

2) уведомить другие юниты об обновлении

3) записать «update-action» в историю / журнал / что угодно еще (возможно, вы захотите иметь возможность воспроизвести всю игру после ее завершения, как в фильме).

....

n) любое другое взаимодействие между вашим Player-объектом и его окружением.

Во всех этих случаях вам придется изменить метод обновления, например:

public void update(long timeElapsed) {
   dosmth();

   redraw();
   notifyUnits();
   updateHistory();
}

Это очень раздражает. Вот почему в таких случаях следует использовать Observer-pattern. Ваш объект должен уведомить всех слушателей, что он был обновлен. Слушатели (GraphicsContext, History, unit) будут правильно реагировать, и ваша программа будет легко обслуживаться, потому что все ее части будут отвечать только за одну конкретную задачу.

3 голосов
/ 08 июня 2010

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

2 голосов
/ 08 июня 2010

Это нормально, но если у вас много разных объектов, все со спрайтами, позициями и скоростями, которые требуют обновления, тогда будет много репликации.Вы можете выдвинуть местоположение, скорость в базовый класс, но это жестко привязывает тип движения.Лучше отделить движение от самого объекта.

Например, рассмотрим мяч, подпрыгивающий вверх и вниз.Это не легко моделировать только с одной скоростью.Вместо этого создайте класс Motion с ConstantMotiion (для скорости) и BounceMotion для отскока.Затем класс движения заботится об обновлении состояния позиции объекта от кадра к кадру.

1 голос
/ 16 июня 2010

Я попал в этот паттерн раньше, вот мой вклад:

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

Если по какой-то причине вы хотите выполнить рендеринг на разных платформах, этот подход не работает из-за отсутствияразделение, опять же плагин рендерер лучше подход

1 голос
/ 09 июня 2010

Полезно взглянуть на возможность того, что большинство объектов в системе должны изменять только специфичные для движка дескрипторы (скорость, активная анимация) и позволять движку заботиться о реальном эффекте. Есть несколько исключений из этого (обычно маркеры и другие эффекты с одним тиком), но в целом эти системы полагаются на один универсальный тик, который обновляет игру. Основная причина этого, как отметил mdma в своем комментарии к ответу Романа, заключается в том, что реальный движок делает гораздо больше, чем простые отдельные операции рендеринга. Точно так же физический движок обновит весь мир, вычисляя объемы столкновений с учетом движения субтиков.

Загрузка спрайта обычно заключается в загрузке ресурсов всей карты и последующей адресации этого спрайта по имени в хранилище ресурсов карты.

Столкновение обычно обрабатывается отдельным физическим движком, см. Выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...