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
Los componentes factory se usan para generar dinámicamente objetos de juego desde un conjunto de objetos en un juego en ejecución.
Cuando agregas un componente factory a un objeto de juego, especificas en la propiedad Prototype qué archivo de objeto de juego debe usar la factory como prototipo (también conocido como “prefabs” o “blueprints” en otros motores) para todos los objetos de juego nuevos que crea.


Para activar la creación de un objeto de juego, llama a 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() toma 5 parámetros:
url[position]vector3. Si no especificas una posición, el objeto de juego se genera en la posición del objeto de juego que llama a factory.create().[rotation]quat.[properties][scale]number (mayor que 0) que especifica un escalado uniforme a lo largo de todos los ejes. También puedes proporcionar un vector3 donde cada componente especifica el escalado a lo largo del eje correspondiente.Por ejemplo:
-- factory.script
local p = go.get_position()
p.y = vmath.lerp(math.random(), min_y, max_y)
local component = "#star_factory"
-- Genera sin rotación pero con escala doble.
-- Define la propiedad score de la estrella en 10.
factory.create(component, p, nil, { score = 10 }, 2.0) -- <1>
-- 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

Actualmente Defold no admite el escalado no uniforme de formas de colisión. Si proporcionas un valor de escala no uniforme, por ejemplo vmath.vector3(1.0, 2.0, 1.0), el sprite se escalará correctamente, pero las formas de colisión no.
El mecanismo de direccionamiento de Defold permite acceder a cada objeto y componente en un juego en ejecución. El manual de direccionamiento entra en bastante detalle sobre cómo funciona el sistema. Es posible usar el mismo mecanismo de direccionamiento para objetos de juego generados y sus componentes. Muy a menudo basta con usar el id del objeto generado, por ejemplo al enviar un mensaje:
local function create_hunter(target_id)
local id = factory.create("#hunterfactory")
msg.post(id, "hunt", { target = target_id })
return id
end
El paso de mensajes al propio objeto de juego en vez de a un componente específico enviará de hecho el mensaje a todos los componentes. Normalmente esto no es un problema, pero conviene tenerlo en cuenta si el objeto tiene muchos componentes.
Pero ¿qué ocurre si necesitas acceder a un componente específico en un objeto de juego generado, por ejemplo para desactivar un objeto de colisión o cambiar la imagen de un sprite? La solución es construir una URL a partir del id del objeto de juego y el id del componente.
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
Cuando llamas a factory.create() obtienes el id del nuevo objeto de juego, lo que te permite guardar el id para usarlo como referencia en el futuro. Un uso común es generar objetos y agregar sus ids a una tabla para poder eliminarlos todos más adelante, por ejemplo al restablecer la disposición de un nivel:
-- spawner.script
self.spawned_coins = {}
...
-- Genera una moneda y guárdala en la tabla "coins".
local id = factory.create("#coinfactory", coin_position)
table.insert(self.spawned_coins, id)
Y luego más adelante:
-- spawner.script
-- Elimina todas las monedas generadas.
for _, coin_id in ipairs(self.spawned_coins) do
go.delete(coin_id)
end
-- o alternativamente
go.delete(self.spawned_coins)
También es común que quieras que el objeto generado conozca el objeto de juego que lo generó. Un caso sería algún tipo de objeto autónomo que solo puede generarse de a uno por vez. El objeto generado entonces necesita informar al generador cuando se elimina o se inactiva para que pueda generarse otro:
-- spawner.script
-- Genera un drone y define su padre como la URL de este componente de script
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
Y la lógica del objeto generado:
-- drone.script
go.property("parent", msg.url())
...
function final(self)
-- Estoy muerto.
msg.post(self.parent, "drone_dead")
end
Al marcar la casilla Load Dynamically en las propiedades de la factory, el motor pospone la carga de los recursos asociados con la factory.

Con la casilla desmarcada, el motor carga los recursos del prototipo cuando se carga el componente factory, de modo que estén listos inmediatamente para generar objetos.
Con la casilla marcada, tienes dos opciones de uso:
factory.create() cuando quieras generar objetos. Esto cargará los recursos de forma síncrona, lo que puede causar una pausa breve, y luego generará nuevas instancias.
function init(self)
-- No se carga ningún recurso de factory cuando se carga
-- la colección padre de la factory. Llamar a create sin
-- haber llamado a load creará los recursos de forma síncrona.
self.go_id = factory.create("#factory")
end
function final(self)
-- Elimina objetos de juego. Reducirá el contador de referencia de los recursos.
-- En este caso los recursos se eliminan porque el componente factory
-- no mantiene ninguna referencia.
go.delete(self.go_id)
-- Llamar a unload no hará nada porque factory no mantiene referencias
factory.unload("#factory")
end
factory.load() para cargar explícitamente los recursos de forma asíncrona. Cuando los recursos estén listos para generar objetos, se recibe un callback.
function load_complete(self, url, result)
-- La carga terminó, los recursos están listos para generar objetos
self.go_id = factory.create(url)
end
function init(self)
-- No se carga ningún recurso de factory cuando se carga
-- la colección padre de la factory. Llamar a load cargará los recursos.
factory.load("#factory", load_complete)
end
function final(self)
-- Elimina el objeto de juego. Reducirá el contador de referencia de los recursos.
-- En este caso los recursos no se eliminan porque el componente factory
-- todavía mantiene una referencia.
go.delete(self.go_id)
-- Llamar a unload reducirá el contador de referencia de los recursos
-- mantenidos por el componente factory, lo que hará que se destruyan.
factory.unload("#factory")
end
Es posible cambiar qué Prototype puede crear una factory marcando la casilla Dynamic Prototype en las propiedades de la factory.

Cuando la opción Dynamic Prototype está marcada, el componente factory puede cambiar de prototipo usando la función factory.set_prototype(). Ejemplo:
factory.unload("#factory") -- descarga los recursos anteriores
factory.set_prototype("#factory", "/main/levels/enemyA.goc")
local enemy_id = factory.create("#factory")
Cuando la opción Dynamic Prototype está definida, el recuento de componentes de la colección no se puede optimizar, y la colección propietaria usará los recuentos de componentes predeterminados del archivo game.project.
La configuración de proyecto max_instances en Collection related settings limita el número total de instancias de objetos de juego que pueden existir en un mundo (la main.collection cargada al inicio o cualquier mundo cargado mediante un proxy de colección). Todos los objetos de juego que existen en el mundo se cuentan contra ese límite y no importa si se colocaron manualmente en el editor o si se generaron en tiempo de ejecución mediante un script.

Si defines max_instances en 1024 y tienes 24 objetos de juego colocados manualmente en tu colección principal, puedes generar 1000 objetos de juego adicionales. En cuanto elimines un objeto de juego, podrás generar otra instancia.
Puede parecer una buena idea guardar objetos de juego generados en un pool y reutilizarlos. Sin embargo, el motor ya hace pooling de objetos internamente, por lo que la sobrecarga adicional solo hará que todo sea más lento. Es más rápido y más limpio eliminar objetos de juego y generar otros nuevos.