Read this manual in English

Компонент Collection Factory

Компонент Collection Factory используется для порождения групп и иерархий игровых объектов, хранящихся в файлах коллекций, в запущенной игре.

В Defold коллекции обеспечивают эффективный способ создания многократно используемых шаблонов, или “префабов”. Обзор коллекций см. в документации по структурным элементам. Коллекции можно создавать в редакторе или вставлять в игру динамически.

С помощью фабрик коллекций можно порождать содержимое файла коллекции в игровой мир. Это аналогично выполнению порождения фабрикой всех игровых объектов внутри коллекции с последующим построением иерархии “родительский-дочерний” между объектами. Типичным примером является порождение врагов, состоящих из нескольких игровых объектов (например, враг + оружие).

Порождение коллекции

Предположим, нам нужен игровой объект персонаж и отдельный игровой объект щит, дочерний по отношению к персонажу. Мы построим иерархию игровых объектов в файле коллекции и сохраним его под именем “bean.collection”.

Компонент collection proxy используется для создания нового игрового мира, включая отдельный физический мир, на основе коллекции. Доступ к новому миру осуществляется через новый сокет. Все ассеты, содержащиеся в коллекции, загружаются через прокси, когда вы сообщаете прокси о начале загрузки. Это делает их очень полезными, например, для изменения уровней в игре. Однако новые игровые миры сопровождаются довольно большими накладными расходами, поэтому не стоит использовать их для динамической загрузки мелкого контента. За подробностями обращайтесь к документации по прокси-коллекциям.

Collection to spawn

Затем добавляется Collection factory к игровому объекту, который будет осуществлять порождение, и устанавливается “bean.collection” в качестве прототипа компонента:

Collection factory

Теперь порождение объектов “bean” и “shield” — это просто вызов функции collectionfactory.create():

local bean_ids = collectionfactory.create("#bean_factory")

Функция принимает 5 параметров:

url
Идентификатор фабрики коллекций, которая должна породить новый набор игровых объектов.
[position]
(Опционально) Мировая позиция порожденных игровых объектов. Это должен быть vector3. Если не указать позицию, объекты будут порождены в позиции фабрики.
[rotation]
(Опционально) Мировое вращение новых игровых объектов. Это должен быть quat.
[properties]
(Опционально) Lua-таблица с парами id-table, используемая для инициирования порожденных игровых объектов. Как построить эту таблицу, смотрите ниже.
[scale]
(Опционально) Масштаб порождаемых игровых объектов. Масштаб может быть выражен в виде number (больше 0), которое задает равномерное масштабирование по всем осям. Можно также указать vector3, где каждый компонент задает масштабирование по соответствующей оси.

collectionfactory.create() возвращает идентификаторы порожденных игровых объектов в виде таблицы. Ключи таблицы отображают хэш локального идентификатора коллекции каждого объекта на идентификатор каждого объекта в среде выполнения:

Отношение “родительский-дочерний” между “bean” и “shield” не отражается в возвращаемой таблице. Это отношение существует только в графе сцены среды выполнения, то есть в том, как объекты преобразуются вместе. Повторное подчинение объекта никогда не изменяет его id.

local bean_ids = collectionfactory.create("#bean_factory")
go.set_scale(0.5, bean_ids[hash("/bean")])
pprint(bean_ids)
-- DEBUG:SCRIPT:
-- {
--   hash: [/shield] = hash: [/collection0/shield], -- <1>
--   hash: [/bean] = hash: [/collection0/bean],
-- }
  1. Префикс /collection[N]/, где [N] — счетчик, добавляемый к id для уникальной идентификации каждого экземпляра:

Свойства

При порождении коллекции можно передать свойства каждому игровому объекту, построив таблицу, где ключами являются идентификаторы объектов, а значениями — таблицы со свойствами скрипта, которые нужно установить.

local props = {}
props[hash("/bean")] = { shield = false }
local ids = collectionfactory.create("#bean_factory", nil, nil, props)

Предположим, что игровой объект “bean” в “bean.collection” определяет свойство “shield”. Руководство по свойствам скрипта содержит информацию о свойствах сценария.

-- bean/controller.script
go.property("shield", true)

function init(self)
    if not self.shield then
        go.delete("shield")
    end     
end

Динамическая загрузка ресурсов фабрики

Отметив в свойствах фабрики коллекций Load Dynamically, движок откладывает загрузку ресурсов, связанных с фабрикой.

Load dynamically

Если опция не отмечена, движок загружает ресурсы прототипа при загрузке компонента фабрики коллекций, так что они сразу готовы к порождению.

Если опция отмечена, есть два варианта использования:

Синхронная загрузка
Вызовите collectionfactory.create(), когда нужно породить объекты. При этом ресурсы будут загружены синхронно, что может вызвать заминку, а затем будут порождены новые экземпляры.
function init(self)
    -- No factory resources are loaded when the collection factory’s
    -- parent collection is loaded. Calling create without
    -- having called load will create the resources synchronously.
    self.go_ids = collecionfactory.create("#collectionfactory")
end

function final(self)
    -- Delete game objects. Will decref resources.
    -- In this case resources are deleted since the collection
    -- factory component holds no reference.
    go.delete(self.go_ids)

    -- Calling unload will do nothing since factory holds
    -- no references
    collectionfactory.unload("#factory")
end
Асинхронная загрузка
Вызовите collectionfactory.load() для явной асинхронной загрузки ресурсов. Когда ресурсы будут готовы к порождению, будет получен обратный вызов.
function load_complete(self, url, result)
    -- Loading is complete, resources are ready to spawn
    self.go_ids = collectionfactory.create(url)
end

function init(self)
    -- No factory resources are loaded when the collection factory’s
    -- parent collection is loaded. Calling load will load the resources.
    collectionfactory.load("#factory", load_complete)
end

function final(self)
    -- Delete game object. Will decref resources.
    -- In this case resources aren’t deleted since the collection factory
    -- component still holds a reference.
    go.delete(self.go_ids)

    -- Calling unload will decref resources held by the factory component,
    -- resulting in resources being destroyed.
    collectionfactory.unload("#factory")
end