Расширенное использование комнат и порталов

Обратный вызов геймплея

Хотя occlusion culling значительно сокращает количество объектов, которые необходимо визуализировать, существуют и другие затраты на поддержку объектов в игре помимо окончательного рендеринга. Например, в Godot анимированные объекты будут анимироваться независимо от того, появляются они на экране или нет. Это может потребовать больших вычислительных мощностей, особенно для объектов, для которых используется программная оболочка (где оболочка вычисляется на ЦП).

Не бойтесь, комнаты и порталы могут решить эти, и другие проблемы.

Создавая нашу систему комнат для нашего игрового уровня, мы не только располагаем информацией, необходимой для устранения окклюзии, мы также легко создали информацию, необходимую для того, чтобы знать, какие комнаты находятся в локальной "игровой зоне" игрока (или камеры). Если вдуматься, то во многих случаях нет необходимости проводить много симуляций на объектах, которые не имеют ничего общего с игровым процессом.

Область игрового процесса не ограничивается только объектами, которые вы видите перед собой. Монстрам с искусственным интеллектом, позади вас, все равно нужно атаковать вас, когда вы стоите к ним спиной! В Godot игровая область определяется как потенциально видимый набор (PVS) комнат, из комнаты, в которой вы сейчас находитесь. То есть, если есть какая-то часть комнаты, которую можно увидеть из любой части комнаты в которой вы находитесь (даже из угла), она считается в пределах PVS и, следовательно, игровой зоны.

Это работает, потому что, если монстр находится в области, которая полностью вне поля зрения ни вас, ни монстра, вам вряд ли будет интересно, что он делает.

Как монстр узнает, находится ли он в игровой области?

Эта проблема решена, потому что система портала содержит подсистему под названием Монитор игрового процесса, которую можно включать и выключать из RoomManager. При включении, любые объекты, которые перемещаются внутри или за пределами области игрового процесса (будь то путем перемещения себя или перемещения камеры), получат обратные вызовы, чтобы сообщить им об этом изменении.

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

Уведомления могут быть перехвачены в GDScript или других скриптовых языках:

func _notification(what):
        match what:
                NOTIFICATION_ENTER_GAMEPLAY:
                        print("notification enter gameplay")
                NOTIFICATION_EXIT_GAMEPLAY:
                        print("notification exit gameplay")

Сигналы отправляются так же, как и любые другой сигнал. Их можно прикрепить к функциям с помощью editor inspector. Сигналы называются gameplay_entered и gameplay_exited.

На самом деле, вы не просто получаете эти обратные вызовы для ROAMING объектов. Кроме того, комнаты и RoomGroups (которые можно использовать для формирования групп комнат) также могут получать обратные вызовы. Например, вы можете использовать их, чтобы активировать поведение ИИ, когда игрок достигает определенных точек на уровне.

VisbilityNotifiers / VisibilityEnablers

Gameplay callbacks имеют еще одну полезную функцию. По умолчанию, в Godot, анимация и физика по-прежнему обрабатываются независимо от того, находится ли объект в поле зрения. Это может снизить производительность, особенно при использовании программного скиннинга.

Решением этой проблемы является узел :reef:`Visibility Notifier<class_Visibility Notifier>`, и его несколько более простой в использовании вариант, узел VisibilityEnabler. Visibility Enabled можно использовать для отключения анимации и физики сна, когда объект находится за пределами усеченной пирамиды обзора. Вы делаете это, просто размещая узел с включенной видимостью в своей подсцене (например, для монстра). Он сделает все остальное. Подробную информацию см. в документации Visibility Enabled.

../../../_images/visibility_enabler.png

Что, если бы VisibilityEnabler мог отключать объекты, когда они были отбракованы? Ну оказывается VisibilityEnabler может. Все, что вам нужно сделать, это включить Gameplay Monitor в RoomManager, а все остальное произойдет автоматически.

RoomGroups

RoomGroup – это специальный узел, который позволяет вам иметь дело с группой комнат одновременно, вместо того, чтобы писать код для каждой из них по отдельности. Это особенно полезно в сочетании с обратными вызовами игрового процесса. Самое важное использование RoomGroups — разграничить «внутреннюю» и «внешнюю» области.

../../../_images/roomgroups.png

Например, находясь снаружи, вы можете использовать DirectionalLight для представления солнца. Когда внешняя группа RoomGroup получает обратный вызов «enter gameplay», вы можете включить свет и выключить его, когда RoomGroup выходит из игрового процесса. При выключенном свете производительность возрастет, так как нет необходимости рендерить его в помещении.

Это пример простого сценария RoomGroup для включения и выключения DirectionalLight. Обратите внимание, что вы также можете использовать сигналы для обратных вызовов (выбор за вами):

../../../_images/roomgroup_notification.png

Совет

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

Internal Rooms

Есть еще одна хитрость, которую RoomGroups припасли в рукаве. Очень распространено желание иметь игровой уровень со смешанной внешней и внутренней средой. Мы уже упоминали, что помещения могут использоваться для представления как комнат в здании, так и областей ландшафта, таких как каньон.

What happens if you wish to have a house in a terrain 'room'?

С описанной до сих пор функциональностью вы можете сделать это - вам нужно будет разместить порталы вокруг внешней части дома, образуя ненужные комнаты над домом. Это было сделано во многих играх. Но что, если бы существовал более простой способ?

It turns out there is a simpler way of handling this scenario. Godot supports rooms **within* rooms* (we will call them "internal rooms"). That is, you can place a house within a terrain room, or even a building, or set of buildings, and even have exit portals in different terrain rooms!

Чтобы создать внутренние комнаты, вам не нужно размещать комнату внутри другой комнаты в дереве сцен — на самом деле вы получите предупреждение, если попытаетесь это сделать. Вместо этого создайте их как обычные комнаты. Внутренние комнаты должны быть сгруппированы вместе с RoomGroup в качестве родителя. Если вы посмотрите в инспекторе на группу комнат, там есть Room Group Priority , который по умолчанию равен 0.

Если вы хотите, чтобы комната или набор комнат были внутренними, установите для приоритета более высокое значение, чем для внешней (окружающей) комнаты, используя класс RoomGroup.

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

Единственные отличия:

  • Порталы между внутренними помещениями и внешними помещениями всегда должны размещаться во внутреннем (внутреннем) помещении.

  • Порталы внутренних помещений не считаются частью ограждения наружных помещений.

  • STATIC и DYNAMIC объекты из внешних комнат не будут растягиваться во внутренние комнаты. Если вы хотите, чтобы объекты пересекали эти порталы, разместите их во внутренней комнате. Это делается для предотвращения растягивания больших объектов, таких как участки местности, на целые здания и рендеринга, когда это не требуется.

Пример внутренней комнаты

Палатка представляет собой простую комнату внутри комнаты с ландшафтом (которая содержит землю, деревья и т. д.).

../../../_images/tent.png

Примечание

Чтобы использовать внутренние помещения для зданий, обычно рекомендуется отделить внутреннюю сетку здания от внешней. Экстерьер можно разместить во внешней комнате (чтобы его было видно снаружи, но не изнутри), а интерьер нужно разместить во внутренней комнате (чтобы он был виден только внутри или через портал).

../../../_images/tent_terrain.png

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

Scene is 'Diorama Eco scene' by Odo, with slight changes for illustration purposes. CC Attribution

Internal room scenes

Давайте подробно рассмотрим еще один практический пример для открытого мира. Мы хотим разместить дома (как внутренние комнаты) на острове, но сделать каждый дом отдельной сценой, содержащей как внутреннюю *, так и * внешнюю сетку дома.

../../../_images/house_scene.png

Мы создали узел Room (который станет внутренней комнатой), в который мы поместили внутренние сетки. Мы также создали портал без ссылок (поэтому будет использоваться автоссылка). Внешняя сетка не находится внутри комнаты. Он будет размещен автоматически, и мы планируем разместить его во внешней комнате.

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

Чтобы обойти эту проблему, существует специальная настройка, позволяющая указать предпочтение авторазмещению во внешней комнате. У каждого объекта есть настройка Приоритет авторазмещения. При значении 0 предпочтения отсутствуют (объект будет помещен в комнату с наивысшим приоритетом).

Однако, если мы установим этот приоритет авторазмещения, например, на -1 то авторазмещение всегда будет выбирать комнату с приоритетом -1 (если она присутствует в этом месте). Таким образом, если мы установим приоритет внешней комнаты на -1, это всегда будет помещать нашу внешнюю часть в нашу «внешнюю» комнату.

../../../_images/autoplace_priority.png

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

Примечание

Поскольку приоритет авторазмещения по умолчанию равен 0 вы не можете принудительно помещать объекты в RoomGroups с приоритетом 0. Однако существует множество доступных значений приоритета, поэтому на практике это не должно быть проблемой.

Финальная сцена выглядит примерно так: дома расположены там, где вы хотите, в гигантской внешней комнате.

../../../_images/island.png

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