Компонент Collection Proxy используется для динамической загрузки и выгрузки новых игровых “миров”, основываясь на содержимом файла коллекции. Они могут использоваться для реализации переключения между игровыми уровнями, экранами графического интерфейса, загрузки и выгрузки повествовательных “сцен” на протяжении уровня, загрузки/выгрузки мини-игр и многого другого.
Defold организует все игровые объекты в коллекции. Коллекция может содержать игровые объекты и другие коллекции (то есть субколлекции). Прокси-коллекции позволяют разделить содержимое на отдельные коллекции и затем динамически управлять загрузкой и выгрузкой этих коллекций с помощью скриптов.
Прокси-коллекции отличаются от фабрик коллекций. Фабрика коллекций внедряет содержимое коллекции в текущий игровой мир. Прокси-коллекции создают новый игровой мир во время выполнения и, следовательно, имеют другие сценарии использования.
Добавьте прокси-коллекцию к игровому объекту, кликнув ПКМ на игровом объекте и выбрав Add Component ▸ Collection Proxy из контекстного меню.
В свойстве Collection укажите ссылку на коллекцию, которую необходимо динамически загрузить в среду выполнения позднее. Ссылка является статической и гарантирует, что все содержимое коллекции, на которую ссылаются, в конечном счете окажется в игре.
(Содержимое можно исключить из сборки и загрузить вместо него код, отметив опцию Exclude и используя Live-обновление.)
Когда движок Defold запускается, он загружает и инстанцирует все игровые объекты из загрузочной (bootstrap) коллекции в среду выполнения. Затем он инициализирует и активирует игровые объекты и их компоненты. Какая загрузочная коллекция должна использоваться движком, указывается в настройках проекта. По договоренности этот файл коллекции обычно называется “main.collection”.
Для размещения игровых объектов и их компонентов движок выделяет память, необходимую для всего “игрового мира”, в который инстанцируется содержимое загрузочной коллекции. Кроме того, создается отдельный физический мир для любых объектов столкновений и физических симуляций.
Поскольку скрипты должны иметь возможность обращаться ко всем объектам в игре, даже извне загрузочного мира, им присваивается уникальное имя: свойство Name, которое задается в файле коллекции:
Если загружаемая коллекция содержит прокси-коллекции, коллекции, на которые они ссылаются, автоматически не загружаются. Необходимо контролировать загрузку этих ресурсов с помощью скриптов.
Динамическая загрузка коллекции посредством прокси осуществляется путем отправки сообщения load
компоненту прокси из скрипта:
-- Сказать прокси "myproxy", чтобы он начал загрузку.
msg.post("#myproxy", "load")
Прокси укажет движку выделить место для нового мира. Также будет создана отдельная среда выполнения физики и инстанцируются все игровые объекты в коллекции.
Новый мир получает свое имя из свойства Name в файле коллекции, в данном примере оно установлено в “mylevel”. Имя должно быть уникальным. Если Name, заданное в файле коллекции, уже используется для загруженного мира, движок сообщит об ошибке конфликта имен:
ERROR:GAMEOBJECT: The collection 'default' could not be created since there is already a socket with the same name.
WARNING:RESOURCE: Unable to create resource: build/default/mylevel.collectionc
ERROR:GAMESYS: The collection /mylevel.collectionc could not be loaded.
Когда движок закончит загрузку коллекции, прокси-коллекция отправит сообщение "proxy_loaded"
обратно скрипту, который отправил сообщение "load"
. Затем скрипт может инициализировать и активировать коллекцию в качестве реакции на это сообщение:
function on_message(self, message_id, message, sender)
if message_id == hash("proxy_loaded") then
-- Новый мир загружен. Инициировать и активировать его.
msg.post(sender, "init")
msg.post(sender, "enable")
...
end
end
"load"
"proxy_loaded"
, когда все будет готово."async_load"
"proxy_loaded"
, когда все будет готово."init"
"enable"
Имя Name, заданное в свойствах файла коллекции, используется для обращения к игровым объектам и компонентам в загруженном мире. Если, например, создать объект-загрузчик в коллекции начальной загрузки, может понадобиться взаимодействовать с ним из любой загруженной коллекции:
-- сообщить загрузчику о необходимости загрузить следующий уровень:
msg.post("main:/loader#script", "load_level", { level_id = 2 })
Чтобы выгрузить загруженную коллекцию, необходимо отправить сообщения, соответствующие обратным этапам загрузки:
-- unload the level
msg.post("#myproxy", "disable")
msg.post("#myproxy", "final")
msg.post("#myproxy", "unload")
"disable"
"final"
final()
всех скриптов."unload"
Если более тонкий контроль не требуется, можно отправить сообщение "unload"
напрямую, без предварительной деактивации и финализации коллекции. Тогда прокси автоматически отключит и завершит коллекцию перед ее выгрузкой.
Когда Collection Proxy закончит выгрузку коллекции, он отправит сообщение "proxy_unloaded"
обратно в скрипт, который отправил сообщение "unload"
:
function on_message(self, message_id, message, sender)
if message_id == hash("proxy_unloaded") then
-- Ok, мир выгружен...
...
end
end
Обновления прокси-коллекции можно масштабировать, изменяя временной шаг. Это означает, что даже если игра имеет постоянную частоту 60 FPS, прокси может обновляться с большей или меньшей скоростью, влияя на такие аспекты, как:
dt
, переданное в update()
Можно также установить режим обновления, который позволяет контролировать, должно ли масштабирование выполняться дискретно (что имеет смысл только при коэффициенте масштабирования менее 1.0) или непрерывно.
Управление коэффициентом масштабирования и режимом масштабирования осуществляется путем отправки прокси сообщения set_time_step
:
-- обновлять загруженный мир на 1/5 скорости.
msg.post("#myproxy", "set_time_step", {factor = 0.2, mode = 1}
Чтобы увидеть, что происходит при изменении временного шага, мы можем создать объект со следующим кодом в скрипте и поместить его в коллекцию, временной шаг которой мы изменяем:
function update(self, dt)
print("update() with timestep (dt) " .. dt)
end
При шаге по времени 0.2 мы получаем следующий результат в консоли:
INFO:DLIB: SSDP started (ssdp://192.168.0.102:54967, http://0.0.0.0:62162)
INFO:ENGINE: Defold Engine 1.2.37 (6b3ae27)
INFO:ENGINE: Loading data from: build/default
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0.016666667535901
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0.016666667535901
update()
по-прежнему вызывается 60 раз в секунду, но значение dt
меняется. Мы видим, что только 1/5 (0.2) вызовов update()
будет иметь dt
равное 1/60 (что соответствует 60 FPS) — остальные равны нулю. Все физические симуляции также будут обновляться в соответствии с этим dt
и продвигаться только в 1/5 кадров.
Функциональность временного шага коллекции можно использовать для приостановки игры, например, при отображении всплывающего окна или когда окно потеряло фокус. Используйте msg.post("#myproxy", "set_time_step", {factor = 0, mode = 0})
для паузы и msg.post("#myproxy", "set_time_step", {factor = 1, mode = 1})
для возобновления.
За подробностями обращайтесь к set_time_step
.
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB