Должен ли объект в 2D-игре отображать сам себя?


16

Я делаю 2D-игру, похожую на уличного бойца, которая не основана на тайлах. Обычно люди рекомендуют отдавать сущности визуализирующему объекту, а не самим, но кажется, что обратное лучше,

Почему одно лучше другого?

Благодарность


Почему вы думаете, что обратное лучше?

1
@Martin, потому что объект будет подсказывать, какое растровое изображение использовать в любом случае, так почему бы просто не сделать object-> render ();
jmasterx

Ответы:


11

Пара соображений:

  • как вы упомянули, каждый спрайт должен был бы «намекнуть» о том, какое растровое изображение использовать, но если объект должен визуализировать себя. Что это за «подсказка»? Если это ссылка на другое растровое изображение, таблицу спрайтов и т. Д. Для каждого спрайта, то вы можете использовать больше памяти, чем необходимо, или иметь проблемы с управлением этой памятью. Преимущество отдельного средства рендеринга заключается в том, что за управление активами отвечает только один класс. Тем не менее, в SF2-подобных файтингах у вас может быть только два спрайта;)

  • как уже упоминалось в другом месте, когда вы хотите изменить свой графический API, вы должны изменить код для всех ваших спрайтов.

  • рендеринг редко выполняется без ссылки на некоторый графический контекст. Так что либо существует глобальная переменная, которая представляет эту концепцию, либо каждый спрайт имеет интерфейс с render (GraphicalContext ctx). Это смешивает графический API и логику вашей игры (которую некоторые люди считают нелегкой) и может вызвать проблемы при компиляции.

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

В общем, я предпочитаю системы, в которых рендеринг выполняется отдельным классом. Это не означает, что ваши спрайты не могут иметь некоторые атрибуты, которые «графически связаны» (имя анимации, кадр анимации, высота x ширина, идентификатор спрайта и т. Д.), Если это облегчает написание рендерера или делает его более эффективным.

И я не знаю, применимо ли это к 3D (где понятие ячеек и переменная координат, которую вы используете, возможно, будут привязаны к вашему 3D API; тогда как x, y, h, w в значительной степени независимы от любого 2D API).

Надеюсь, это поможет.


11

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

Некоторые преимущества централизованного рендеринга:

  • z-упорядочение:
    если за рендеринг отвечают сами игровые объекты, вам нужно убедиться, что вы называете их в правильном порядке. В противном случае фоновые объекты могут быть нарисованы поверх объектов переднего плана.
    Имея под контролем систему рендеринга, она может выбирать сортировку всех объектов рендеринга, обнаруживать перекрытия во время рендеринга и просто рендерить их, или просто отказаться от упорядочивания всех вместе. Дело в том, что решение может быть легко принято сейчас.
  • Пакетирование
    . Другим очевидным преимуществом контроля системы визуализации является пакетирование. Здесь снова система рендеринга имеет опцию пакетного спрайта, отрисовывающего общий ресурс текстуры. Он может использовать нарезку треугольника для рендеринга всего одним вызовом. Может быть в состоянии кэшировать некоторые расчеты рендеринга Или он может просто визуализировать каждый спрайт без всяких причудливых вещей. (Примечание: возможен пакетный режим, когда каждый объект отображает сам себя, но проблема менее эффективна и более сложна).

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

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


О z-упорядочении, если объекты рисуют сами, не может ли система принять решение о порядке вызова их метода рисования? Я имею в виду, что централизованный или нецентрализованный, по-видимому, не имеет значения в z-упорядочении.
GorillaApe

3

Отказ от ответственности: ваш вопрос не дает подробностей, поэтому я отвечаю общим принципом. Пожалуйста, извините меня, если я неправильно понял ваше использование или «сделать».

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

Ура, Дэвид


Но в этом смысле директор не мог просто сказать acton-> setVisible (false); ?
jmasterx

Даже в случае setVisible (false), это внешний объект, который выполняет рендеринг, проверяя видимую переменную актера и рендеринг ее, только если она истинна.
Нав

Просто сделать актера невидимым не удалит его со сцены. Он также должен прекратить участвовать в столкновениях и т. Д.
finnw

3

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


3

Я использовал дизайн, основанный на наблюдателях. Когда я создал экземпляр класса, который хотел визуализировать, указатель на него хранился в центральном классе Renderer. Когда вы звонитеRenderFrame() , то у рендерера уже есть все существующие объекты, которые ему нужно отрендерить, и для доступа к их свойствам. Сами классы даже не подозревали, что их вообще будут изображать. Этот API был красивым, понятным и простым в использовании.


1
+1 Интересно. Я использовал этот подход для звука при использовании шаблона посетителя для графики. Я подумал, что это имеет больше смысла для звука, потому что, хотя графика и AI работают на одних и тех же часах, звуковой микшер работает на другом, поэтому модель событий проще. Также не критично, если событие движения (которое вызывает изменение панорамирования / реверберации аудиоканала) приходит с опозданием на несколько миллисекунд, но критично, если спрайт отображается в неправильном состоянии.
finnw

2

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

Это зависит от того, что на самом деле делают ваши объекты, когда вы вызываете render (). Пока они просто оборачивают вызовы методов вокруг вашего графического движка, это совершенно нормально, так как логика <-> графическое различие все равно будет дано.

Например, если ваши методы render () в основном удобные и выглядят примерно так:

void MyClass::render(const Graphics &g)
{
    g.draw(this);
}

или

void MyClass::render()
{
   mySprite->render();
}

или

void MyClass::render()
{
    mySprite->UseShader(thatshader);
    mySprite->render();
}

или близко к этому, я не думаю, что это проблема вообще.

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