Что случилось с архитектурой игрового рисования объекта и обновления себя?

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

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?

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

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

18
задан Ricket 8 June 2010 в 19:25
поделиться

6 ответов

Это связывает весь ваш код рендеринга и логики вместе, когда у них мало общего, кроме того, что они концептуально связаны с одной и той же "сущностью". Когда ваш класс становится больше, вы можете оказаться с огромным монолитным Игроком, который просто кошмарно поддерживать. Разделение по границам доменов (рендеринг, AI) делает его более управляемым без необходимости многого терять, поскольку эти домены не сильно пересекаются.

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

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

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

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

Вот много дополнительной информации, если вам интересно.

19
ответ дан 30 November 2019 в 08:10
поделиться

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

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

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

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

....

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

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

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

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

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

3
ответ дан 30 November 2019 в 08:10
поделиться

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

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

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

1
ответ дан 30 November 2019 в 08:10
поделиться

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

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

2
ответ дан 30 November 2019 в 08:10
поделиться

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

3
ответ дан 30 November 2019 в 08:10
поделиться

Я попался на этот паттерн раньше:

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

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

1
ответ дан 30 November 2019 в 08:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: