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
Komponenty Factory służą do dynamicznego tworzenia obiektów gry z puli obiektów w działającej grze.
Gdy dodajesz komponent Factory do obiektu gry, we właściwości Prototype określasz, którego pliku obiektu gry fabryka ma używać jako prototypu dla wszystkich nowych obiektów, które tworzy. W innych silnikach taki prototyp bywa nazywany również “prefabem” albo “blueprintem”.


Aby uruchomić tworzenie obiektu gry, wywołaj 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() przyjmuje 5 parametrów:
url[position]vector3. Jeśli nie podasz pozycji, obiekt gry pojawi się w pozycji komponentu Factory.[rotation]quat.[properties][scale]number większy od 0, co oznacza jednolite skalowanie we wszystkich osiach. Możesz też przekazać vector3, w którym każdy składnik określa skalowanie w odpowiadającej osi.Na przykład:
-- factory.script
local p = go.get_position()
p.y = vmath.lerp(math.random(), min_y, max_y)
local component = "#star_factory"
-- Utwórz obiekt bez obrotu, ale z podwójną skalą.
-- Ustaw wartość właściwości score gwiazdy na 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
self.
Defold nie obsługuje obecnie niejednorodnego skalowania kształtów kolizji. Jeśli podasz wartość niejednorodnego skalowania, na przykład vmath.vector3(1.0, 2.0, 1.0), sprite zostanie przeskalowany poprawnie, ale kształty kolizji już nie.
Mechanizm adresowania Defold pozwala uzyskać dostęp do każdego obiektu i komponentu w działającej grze. Instrukcja Addressing szczegółowo wyjaśnia, jak ten system działa. Tego samego mechanizmu można używać również dla utworzonych obiektów gry i ich komponentów. Często wystarczy użyć id utworzonego obiektu, na przykład podczas wysyłania wiadomości:
local function create_hunter(target_id)
local id = factory.create("#hunterfactory")
msg.post(id, "hunt", { target = target_id })
return id
end
Wysłanie wiadomości do samego obiektu gry zamiast do konkretnego komponentu w praktyce rozsyła ją do wszystkich komponentów tego obiektu. Zwykle nie stanowi to problemu, ale warto o tym pamiętać, jeśli obiekt ma dużo komponentów.
Co jednak zrobić, gdy chcesz uzyskać dostęp do konkretnego komponentu utworzonego obiektu gry, na przykład aby wyłączyć obiekt kolizji albo zmienić obraz sprite’a? Rozwiązaniem jest zbudowanie adresu URL z id obiektu gry i id komponentu.
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
Gdy wywołasz factory.create(), otrzymasz z powrotem id nowego obiektu gry, dzięki czemu możesz zachować je do późniejszego użycia. Jednym z typowych zastosowań jest tworzenie obiektów i dodawanie ich id do tabeli, aby później usunąć je wszystkie, na przykład podczas resetowania układu poziomu:
-- spawner.script
self.spawned_coins = {}
...
-- Utwórz monetę i zapisz ją w tabeli "coins".
local id = factory.create("#coinfactory", coin_position)
table.insert(self.spawned_coins, id)
A później:
-- spawner.script
-- Usuń wszystkie utworzone monety.
for _, coin_id in ipairs(self.spawned_coins) do
go.delete(coin_id)
end
-- albo alternatywnie
go.delete(self.spawned_coins)
Zdarza się też, że chcesz, aby utworzony obiekt wiedział, który obiekt gry go utworzył. Jednym z przykładów jest autonomiczny obiekt, który może istnieć tylko w jednej instancji naraz. Taki obiekt musi poinformować spawner, że został usunięty lub zdezaktywowany, aby można było utworzyć kolejny:
-- spawner.script
-- Utwórz drona i ustaw jego parent na URL tego komponentu skryptu
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
Logika utworzonego obiektu wygląda tak:
-- drone.script
go.property("parent", msg.url())
...
function final(self)
-- Umieram.
msg.post(self.parent, "drone_dead")
end
Po zaznaczeniu pola Load Dynamically we właściwościach Factory silnik odracza ładowanie zasobów powiązanych z fabryką.

Gdy pole nie jest zaznaczone, silnik ładuje zasoby prototypu podczas ładowania komponentu Factory, więc są one od razu gotowe do użycia.
Gdy pole jest zaznaczone, masz dwa sposoby użycia:
factory.create(), gdy chcesz utworzyć obiekty. Spowoduje to synchroniczne załadowanie zasobów, co może wywołać przycięcie, a następnie utworzenie nowych instancji.
function init(self)
-- Gdy zostanie wczytana kolekcja nadrzędna fabryki,
-- zasoby fabryki nie są jeszcze załadowane. Wywołanie create
-- bez wcześniejszego load utworzy zasoby synchronicznie.
self.go_id = factory.create("#factory")
end
function final(self)
-- Usuń obiekt gry. Zmniejszy to licznik referencji zasobów.
-- W tym przypadku zasoby zostaną usunięte, ponieważ komponent
-- fabryki nie trzyma już do nich referencji.
go.delete(self.go_id)
-- Wywołanie unload nic nie zrobi, bo fabryka nie ma referencji.
factory.unload("#factory")
end
factory.load(), aby jawnie załadować zasoby asynchronicznie. Gdy zasoby będą gotowe do tworzenia obiektów, otrzymasz wywołanie zwrotne.
function load_complete(self, url, result)
-- Ładowanie zakończone, zasoby są gotowe do tworzenia instancji.
self.go_id = factory.create(url)
end
function init(self)
-- Gdy zostanie wczytana kolekcja nadrzędna fabryki,
-- zasoby fabryki nie są jeszcze załadowane. Wywołanie load
-- spowoduje ich wczytanie.
factory.load("#factory", load_complete)
end
function final(self)
-- Usuń obiekt gry. Zmniejszy to licznik referencji zasobów.
-- W tym przypadku zasoby nie zostaną usunięte, ponieważ komponent
-- fabryki nadal trzyma do nich referencję.
go.delete(self.go_id)
-- Wywołanie unload zmniejszy licznik referencji zasobów
-- trzymanych przez komponent fabryki, co doprowadzi do ich usunięcia.
factory.unload("#factory")
end
Można zmienić, który Prototype fabryka może tworzyć, zaznaczając pole Dynamic Prototype we właściwościach komponentu.

Gdy opcja Dynamic Prototype jest włączona, komponent Factory może zmieniać prototyp przy użyciu funkcji factory.set_prototype(). Przykład:
factory.unload("#factory") -- zwolnij poprzednie zasoby
factory.set_prototype("#factory", "/main/levels/enemyA.goc")
local enemy_id = factory.create("#factory")
Gdy opcja Dynamic Prototype jest włączona, liczby komponentów w kolekcji nie można zoptymalizować, a kolekcja właściciela będzie używać domyślnych liczników komponentów z pliku game.project.
Ustawienie projektu max_instances w sekcji Collection related settings ogranicza łączną liczbę instancji obiektów gry, które mogą istnieć w świecie. Dotyczy to main.collection wczytywanej przy starcie i każdego świata załadowanego przez pełnomocnika kolekcji. Do tego limitu wliczają się wszystkie obiekty gry istniejące w świecie, niezależnie od tego, czy zostały ręcznie umieszczone w edytorze, czy utworzone w czasie działania przez skrypt.

Jeśli ustawisz max_instances na 1024 i masz 24 ręcznie umieszczone obiekty gry w głównej kolekcji, możesz utworzyć jeszcze 1000 obiektów gry. Gdy tylko usuniesz jakiś obiekt gry, możesz utworzyć kolejną instancję.
Może się wydawać, że dobrym pomysłem jest przechowywanie utworzonych obiektów gry w puli i ponowne ich wykorzystywanie. Silnik i tak wykonuje takie ponowne używanie obiektów wewnętrznie, więc dodatkowy narzut tylko spowolni działanie. Szybciej i czyściej jest usuwać obiekty gry i tworzyć nowe.