Отказ от ответственности: я знаю, что такое шаблон сущности и не использую его.
Я много читал о разделении объекта и рендеринга. О том, что игровая логика должна быть независимой от базового движка рендеринга. Это все прекрасно и прекрасно, и это имеет смысл, но это также вызывает много других проблем:
- необходимость синхронизации между логическим объектом и объектом рендеринга (тот, который сохраняет состояние анимации, спрайтов и т. д.)
- необходимо открыть логический объект для публики, чтобы объект рендеринга мог считывать фактическое состояние логического объекта (часто это приводит к тому, что логический объект легко трансформируется в тупой объект получения и установки)
Это не похоже на хорошее решение для меня. С другой стороны, очень интуитивно можно представить объект в виде его трехмерного (или двухмерного) представления, а также очень простого в обслуживании (и, возможно, гораздо более инкапсулированного).
Есть ли способ сохранить графическое представление и игровую логику вместе (избегая проблем с синхронизацией), но абстрагировать движок рендеринга? Или есть способ разделить игровую логику и рендеринг, который не вызывает вышеуказанных недостатков?
(возможно, с примерами, я не очень хорошо разбираюсь в абстрактных речах)
источник
Ответы:
Предположим, у вас есть сцена, состоящая из мира , игрока и босса. О, и это игра от третьего лица, поэтому у вас также есть камера .
Итак, ваша сцена выглядит так:
(По крайней мере, это основные данные . Как вы их содержите, зависит от вас.)
Вы хотите обновлять и визуализировать сцену только тогда, когда играете в игру, а не в режиме паузы или в главном меню ... поэтому вы присоединяете ее к состоянию игры!
Теперь в вашем игровом состоянии есть сцена. Далее вы хотите запустить логику на сцене и визуализировать сцену. Для логики, вы просто запускаете функцию обновления.
Таким образом, вы можете сохранить всю игровую логику в
Scene
классе. И просто для справки, система компонентов сущности может сделать это следующим образом:В любом случае, теперь вам удалось обновить свою сцену. Теперь вы хотите отобразить это! Для чего мы делаем что-то похожее на вышеперечисленное:
Вот и ты. RenderSystem считывает информацию со сцены и отображает соответствующее изображение. Упрощенно, метод рендеринга сцены может выглядеть так:
Действительно упрощенный, вам все равно придется, например, применять ротацию и перевод в зависимости от того, где находится ваш игрок и куда он смотрит. (Мой пример - 3D-игра, если вы пойдете с 2D, это будет прогулка в парке).
Надеюсь, это то, что вы искали? Как можно вспомнить из вышесказанного, система рендеринга не заботится о логике игры . Он использует только текущее состояние сцены для рендеринга, то есть извлекает из него необходимую информацию для рендеринга. А логика игры? Неважно, что делает рендерер. Черт, все равно, отображается ли он вообще!
И вам не нужно прикреплять информацию рендеринга к сцене. Этого должно быть достаточно, чтобы визуализатор знал, что ему нужно визуализировать орка. Вы уже загрузили модель орка, которую рендер будет знать для отображения.
Это должно удовлетворить ваши требования. Графическое представление и логика связаны , потому что они оба используют одни и те же данные. Все же они отделены , потому что ни один не полагается на другого!
РЕДАКТИРОВАТЬ: И просто чтобы ответить, почему кто-то сделал бы это так? Потому что это проще, это самая простая причина. Вам не нужно думать о том, "что-то и такое произошло, теперь я должен обновить графику". Вместо этого вы заставляете вещи происходить, и каждый кадр игры смотрит на то, что происходит в данный момент, и интерпретирует это некоторым образом, давая вам результат на экране.
источник
Ваш заголовок задает другой вопрос, нежели содержание вашего тела. В заголовке вы спрашиваете, почему логика и рендеринг должны быть разделены, а в теле вы спрашиваете о реализации систем логики / графики / рендеринга.
Второй вопрос был рассмотрен ранее , поэтому я сосредоточусь на первом вопросе.
Причины разделения логики и рендеринга:
В настройках ООП создание новых объектов требует затрат, но, по моему опыту, стоимость системных ресурсов - это небольшая цена за способность думать и реализовывать конкретные вещи, которые мне нужно выполнить.
источник
Этот ответ только для того, чтобы построить интуицию о важности разделения рендеринга и логики, а не прямо предлагать практические примеры.
Давайте предположим, что у нас есть один большой слон , никто в комнате не может видеть всего слона. Может быть, все даже не согласны с тем, что это на самом деле. Потому что каждый видит разную часть слона и может иметь дело только с этой частью. Но, в конце концов, это не меняет того факта, что это большой слон.
Слон представляет игровой объект со всеми его деталями. Но на самом деле никому не нужно знать все о слоне (игровом объекте), чтобы иметь возможность выполнять его функции.
Соединение игровой логики и рендеринга на самом деле похоже на то, чтобы заставить всех увидеть всего слона. Если что-то изменилось, каждый должен знать об этом. Хотя в большинстве случаев им нужно видеть только ту часть, которая им интересна. Если что-то изменило человека, который знает об этом, ему нужно лишь рассказать другому человеку о результате этого изменения, это то, что ему важно. (думайте об этом как об общении через сообщения или интерфейсы).
Упомянутые вами пункты не являются откатами, они отстают только в том случае, если существует больше зависимостей, чем должно быть в движке, иными словами, системы видят части слона больше, чем должны были. А это значит, что двигатель не был «правильно» сконструирован.
Синхронизация с формальным определением необходима вам только в том случае, если вы используете многопоточный движок, в котором логика и рендеринг размещены в двух разных потоках, и даже движок, который требует большой синхронизации между системами, не особенно хорошо разработан.
В противном случае, естественным способом решения такого случая является проектирование системы ввода / вывода. Обновление выполняет логику и выводит результат. Рендеринг подается только с результатами обновления. Вам действительно не нужно все подвергать. Вы только выставляете Интерфейс, который связывается между двумя стадиями. Связь между различными частями движка должна осуществляться через абстракции (интерфейсы) и / или сообщения. Никакая внутренняя логика или состояния не должны быть разоблачены.
Давайте рассмотрим простой пример графа сцены, чтобы объяснить идею.
Обновление обычно выполняется через один цикл, называемый игровым циклом (или, возможно, через несколько игровых циклов, каждый из которых выполняется в отдельном потоке). После того, как в цикле обновляется игровой объект. Нужно только сообщить через сообщения или интерфейсы, что объекты 1 и 2 обновлены, и передать их с окончательным преобразованием.
Система рендеринга принимает только окончательное преобразование и не знает, что на самом деле изменилось в объекте (например, произошло конкретное столкновение и т. Д.). Теперь для визуализации этого объекта ему нужен только идентификатор этого объекта и окончательное преобразование. После этого рендер будет подавать рендеринг API с сеткой и финальным преобразованием, ничего не зная.
источник