This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
Компоненти-фабрики (factory components) використовуються для динамічного створення ігрових об’єктів (game objects) із пулу об’єктів у запущеній грі.
Коли ви додаєте компонент-фабрику до ігрового об’єкта, у властивості Prototype ви вказуєте, який файл ігрового об’єкта фабрика має використовувати як прототип (в інших рушіях також відомий як «префаб» (prefab) або «шаблон» (blueprint)) для всіх нових ігрових об’єктів, які вона створює.


Щоб створити ігровий об’єкт, викличте factory.create():
-- factory.script
local p = go.get_position()
p.y = vmath.lerp(math.random(), min_y, max_y)
local component = "#star_factory"
factory.create(component, p)

factory.create() приймає 5 параметрів:
url[position]vector3. Якщо ви не вкажете позицію, ігровий об’єкт буде створено в позиції ігрового об’єкта, який викликає factory.create().[rotation]quat.[properties][scale]number (більшим за 0), яке визначає рівномірне масштабування вздовж усіх осей. Також можна передати vector3, у якому кожен компонент визначає масштабування вздовж відповідної осі.Наприклад:
-- factory.script
local p = go.get_position()
p.y = vmath.lerp(math.random(), min_y, max_y)
local component = "#star_factory"
-- Spawn with no rotation but double scale.
-- Set the score of the star to 10.
factory.create(component, p, nil, { score = 10 }, 2.0) -- <1>
score ігрового об’єкта зірки.-- star.script
go.property("score", 1) -- <1>
local speed = -240
function update(self, dt)
local p = go.get_position()
p.x = p.x + speed * dt
if p.x < -32 then
go.delete()
end
go.set_position(p)
end
function on_message(self, message_id, message, sender)
if message_id == hash("collision_response") then
msg.post("main#gui", "add_score", {amount = self.score}) -- <2>
go.delete()
end
end
score визначено зі значенням за замовчуванням.score як до значення, збереженого в self.
Наразі Defold не підтримує нерівномірне масштабування форм колізій. Якщо ви передасте значення нерівномірного масштабу, наприклад vmath.vector3(1.0, 2.0, 1.0), спрайт буде масштабовано правильно, а форми колізій — ні.
Механізм адресації Defold дає змогу звертатися до кожного об’єкта й компонента в запущеній грі. У посібнику з адресації докладно описано, як працює ця система. Той самий механізм адресації можна використовувати для створених ігрових об’єктів та їхніх компонентів. Часто достатньо використати ідентифікатор створеного об’єкта, наприклад, для надсилання повідомлення:
local function create_hunter(target_id)
local id = factory.create("#hunterfactory")
msg.post(id, "hunt", { target = target_id })
return id
end
Надсилання повідомлення самому ігровому об’єкту замість конкретного компонента фактично надсилає його всім компонентам. Зазвичай це не проблема, але варто пам’ятати про це, якщо об’єкт має багато компонентів.
А що робити, якщо потрібно звернутися до конкретного компонента створеного ігрового об’єкта, наприклад, щоб вимкнути об’єкт колізії або змінити зображення спрайта? Для цього потрібно сформувати URL з ідентифікатора ігрового об’єкта та ідентифікатора компонента.
local function create_guard(unarmed)
local id = factory.create("#guardfactory")
if unarmed then
local weapon_sprite_url = msg.url(nil, id, "weapon")
msg.post(weapon_sprite_url, "disable")
local body_sprite_url = msg.url(nil, id, "body")
sprite.play_flipbook(body_sprite_url, hash("red_guard"))
end
end
Коли ви викликаєте factory.create(), у відповідь ви отримуєте ідентифікатор нового ігрового об’єкта, який можна зберегти для подальшого використання. Поширений варіант — створювати об’єкти й додавати їхні ідентифікатори до таблиці, щоб згодом видалити їх усі, наприклад, під час скидання розташування об’єктів рівня:
-- spawner.script
self.spawned_coins = {}
...
-- Spawn a coin and store it in the "coins" table.
local id = factory.create("#coinfactory", coin_position)
table.insert(self.spawned_coins, id)
А згодом:
-- spawner.script
-- Delete all spawned coins.
for _, coin_id in ipairs(self.spawned_coins) do
go.delete(coin_id)
end
-- or alternatively
go.delete(self.spawned_coins)
Також часто потрібно, щоб створений об’єкт знав про ігровий об’єкт, який його створив. Наприклад, це може бути певний тип автономного об’єкта, який може існувати лише в одному екземплярі (instance) одночасно. Тоді створений об’єкт має сповістити об’єкт, який його створив, про своє видалення або деактивацію, щоб можна було створити наступний:
-- spawner.script
-- Spawn a drone and set its parent to the url of this script component
self.spawned_drone = factory.create("#dronefactory", drone_position, nil, { parent = msg.url() })
...
function on_message(self, message_id, message, sender)
if message_id == hash("drone_dead") then
self.spawned_drone = nil
end
end
А логіка створеного об’єкта:
-- drone.script
go.property("parent", msg.url())
...
function final(self)
-- I'm dead.
msg.post(self.parent, "drone_dead")
end
Якщо встановити прапорець Load Dynamically у властивостях фабрики, рушій відкладе завантаження ресурсів, пов’язаних із фабрикою.

Якщо прапорець не встановлено, рушій завантажує ресурси прототипу під час завантаження компонента-фабрики, тому вони одразу готові до створення об’єктів.
Якщо прапорець встановлено, є два варіанти використання:
factory.create(), коли потрібно створити об’єкти. Ресурси буде завантажено синхронно, що може спричинити коротку затримку, а потім буде створено нові екземпляри.
function init(self)
-- No factory resources are loaded when the factory’s parent
-- collection is loaded. Calling create without having called
-- load will create the resources synchronously.
self.go_id = factory.create("#factory")
end
function final(self)
-- Delete game objects. Will decref resources.
-- In this case resources are deleted since the factory component
-- holds no reference.
go.delete(self.go_id)
-- Calling unload will do nothing since factory holds no references
factory.unload("#factory")
end
factory.load(), щоб явно завантажити ресурси асинхронно. Коли ресурси будуть готові до створення об’єктів, буде виконано зворотний виклик.
function load_complete(self, url, result)
-- Loading is complete, resources are ready to spawn
self.go_id = factory.create(url)
end
function init(self)
-- No factory resources are loaded when the factory’s parent
-- collection is loaded. Calling load will load the resources.
factory.load("#factory", load_complete)
end
function final(self)
-- Delete game object. Will decref resources.
-- In this case resources aren’t deleted since the factory component
-- still holds a reference.
go.delete(self.go_id)
-- Calling unload will decref resources held by the factory component,
-- resulting in resources being destroyed.
factory.unload("#factory")
end
Можна змінювати, який Prototype створює фабрика, установивши прапорець Dynamic Prototype у властивостях фабрики.

Коли параметр Dynamic Prototype увімкнено, компонент-фабрика може змінювати прототип за допомогою функції factory.set_prototype(). Приклад:
factory.unload("#factory") -- unload the previous resources
factory.set_prototype("#factory", "/main/levels/enemyA.goc")
local enemy_id = factory.create("#factory")
Коли параметр Dynamic Prototype увімкнено, кількість компонентів колекції (collection) неможливо оптимізувати, і колекція, якій належить фабрика, використовуватиме значення кількості компонентів за замовчуванням із файлу game.project.
Налаштування проєкту Max Instances у розділі Collection задає верхню межу кількості ігрових об’єктів у кожній колекції (світі). Під час збирання Defold може виділити місце для меншої кількості об’єктів, якщо встановить, що це безпечно. До цього ліміту враховуються всі ігрові об’єкти, які одночасно існують у світі, незалежно від того, чи їх розміщено в редакторі, чи створено під час виконання.

Фактичний обсяг виділеного місця залежить від аналізу під час збирання:
Плануючи значення Max Instances, орієнтуйтеся на найбільшу кількість ігрових об’єктів, які можуть одночасно існувати в динамічному світі. Як обчислюються інші обмеження кількості компонентів, див. у розділі Оптимізація максимальної кількості компонентів.
Може здаватися, що зберігати створені ігрові об’єкти в пулі та використовувати їх повторно — добра ідея. Однак рушій уже використовує пул об’єктів усередині, тому додаткові накладні витрати лише сповільнять роботу. Видаляти ігрові об’єкти й створювати нові — швидше та простіше.