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
Komponent Collection proxy służy do dynamicznego wczytywania i zwalniania nowych “światów” gry na podstawie zawartości pliku kolekcji. Można go użyć do przełączania między poziomami, ekranami GUI, wczytywania i zwalniania fabularnych “scen” w trakcie poziomu, wczytywania i zwalniania mini-gier i nie tylko.
Defold organizuje wszystkie obiekty gry w kolekcje. Kolekcja może zawierać obiekty gry i inne kolekcje, czyli podkolekcje. Pełnomocnik kolekcji pozwala rozdzielić zawartość gry na osobne kolekcje, a następnie dynamicznie zarządzać ich wczytywaniem i zwalnianiem ze skryptów.
Pełnomocniki kolekcji różnią się od fabryk kolekcji. Fabryka kolekcji tworzy instancje zawartości kolekcji w bieżącym świecie gry. Pełnomocniki kolekcji tworzą natomiast nowy świat gry w trakcie działania programu, więc mają inne zastosowania.
Dodaj komponent Collection proxy do obiektu gry, klikając prawym przyciskiem myszy obiekt gry i wybierając Add Component ▸ Collection Proxy z menu kontekstowego.
Ustaw właściwość Collection tak, aby wskazywała kolekcję, którą chcesz później dynamicznie wczytać w trakcie działania programu. Referencja jest statyczna i zapewnia, że cała zawartość wskazanej kolekcji trafi do końcowej wersji gry.

(Możesz wyłączyć tę zawartość z kompilacji i pobrać ją później kodem, zaznaczając Exclude i używając funkcji Live update.)
Gdy silnik Defold startuje, wczytuje i instancjonuje wszystkie obiekty gry z kolekcji startowej (bootstrap collection). Następnie inicjalizuje i aktywuje obiekty oraz ich komponenty. To, której kolekcji startowej ma użyć silnik, ustawia się w ustawieniach projektu. Zgodnie z konwencją plik tej kolekcji zwykle nosi nazwę “main.collection”.

Aby pomieścić obiekty gry i ich komponenty, silnik alokuje pamięć potrzebną dla całego “świata gry”, do którego instancjonowana jest zawartość kolekcji startowej. Tworzony jest też oddzielny świat fizyki dla obiektów kolizji i symulacji fizyki.
Ponieważ komponenty skryptowe muszą mieć możliwość adresowania wszystkich obiektów w grze, także spoza świata startowego, każdej kolekcji nadaje się unikalną nazwę przez właściwość Name ustawianą w pliku kolekcji:

Jeśli wczytana kolekcja zawiera komponenty pełnomocnika kolekcji, kolekcje, do których one się odnoszą, nie są wczytywane automatycznie. Musisz sterować wczytywaniem tych zasobów w skryptach.
Dynamiczne wczytywanie kolekcji przez pełnomocnika odbywa się przez wysłanie ze skryptu wiadomości "load" do komponentu pełnomocnika:
-- Poleć pełnomocnikowi "myproxy" rozpocząć wczytywanie.
msg.post("#myproxy", "load")

Pełnomocnik kolekcji nakaże silnikowi zaalokować miejsce na nowy świat i utworzyć osobny świat fizyki. Następnie instancjonowane są wszystkie obiekty gry z kolekcji mylevel.collection.
Nowy świat otrzymuje nazwę z właściwości Name w pliku kolekcji. W tym przykładzie ustawiono ją na mylevel. Nazwa musi być unikalna. Jeśli wartość Name w pliku kolekcji jest już używana przez inny załadowany świat, silnik zgłosi błąd kolizji nazw:
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.
Gdy silnik zakończy wczytywanie kolekcji, pełnomocnik wyśle wiadomość "proxy_loaded" z powrotem do skryptu, który wysłał wiadomość "load". Skrypt może wtedy zainicjalizować i aktywować kolekcję w reakcji na tę wiadomość:
function on_message(self, message_id, message, sender)
if message_id == hash("proxy_loaded") then
-- Nowy świat został wczytany. Zainicjalizuj go i aktywuj.
msg.post(sender, "init")
msg.post(sender, "enable")
...
end
end
"load""proxy_loaded"."async_load""proxy_loaded"."init"init() wszystkich skryptów."enable"Właściwość Name ustawiona w pliku kolekcji służy do adresowania obiektów gry i komponentów wczytanego świata. Jeśli na przykład utworzysz obiekt odpowiedzialny za wczytywanie poziomów, będziesz mógł komunikować się z nim z dowolnej wczytanej kolekcji:
-- poleć loaderowi wczytać następny poziom:
msg.post("main:/loader#script", "load_level", { level_id = 2 })

A jeśli chcesz komunikować się z obiektem gry w wczytanej kolekcji z poziomu loadera, możesz wysłać wiadomość, używając pełnego URL-a obiektu:
msg.post("mylevel:/myobject", "hello")
Nie można bezpośrednio odwoływać się do obiektów gry w wczytanej kolekcji spoza tej kolekcji:
local position = go.get_position("mylevel:/myobject")
-- loader.script:42: wywołana funkcja może uzyskiwać dostęp tylko do instancji w tej samej kolekcji.
Aby zwolnić wczytaną kolekcję, wysyła się do jej pełnomocnika wiadomości odpowiadające odwrotnej kolejności kroków wczytywania:
-- zwolnij poziom
msg.post("#myproxy", "disable")
msg.post("#myproxy", "final")
msg.post("#myproxy", "unload")
"disable""final"final() wszystkich skryptów."unload"Jeśli nie potrzebujesz bardziej szczegółowej kontroli, możesz wysłać wiadomość "unload" bezpośrednio, bez wcześniejszego wyłączania i finalizowania kolekcji. Pełnomocnik automatycznie wyłączy i sfinalizuje kolekcję przed jej zwolnieniem.
Gdy pełnomocnik kolekcji zakończy zwalnianie, odeśle wiadomość "proxy_unloaded" do skryptu, który wysłał wiadomość "unload":
function on_message(self, message_id, message, sender)
if message_id == hash("proxy_unloaded") then
-- Ok, świat został zwolniony...
...
end
end
Aktualizacje kolekcji obsługiwane przez pełnomocnika można skalować przez zmianę kroku czasowego. Oznacza to, że nawet jeśli gra działa ze stałą częstotliwością 60 FPS, pełnomocnik może aktualizować swoją kolekcję szybciej albo wolniej, co wpływa między innymi na:
dt przekazywaną do update()Możesz też ustawić tryb aktualizacji, który pozwala kontrolować, czy skalowanie ma być wykonywane dyskretnie, co ma sens tylko przy współczynniku poniżej 1.0, czy w sposób ciągły.
Współczynnik skalowania kroku czasowego i tryb skalowania kontroluje się przez wysłanie do pełnomocnika wiadomości set_time_step:
-- aktualizuj wczytany świat z jedną piątą prędkości.
msg.post("#myproxy", "set_time_step", {factor = 0.2, mode = 1}
Aby zobaczyć, co się dzieje przy zmianie kroku czasowego, możemy utworzyć obiekt z poniższym kodem w komponencie skryptowym i umieścić go w kolekcji, której krok czasowy zmieniamy:
function update(self, dt)
print("update() with timestep (dt) " .. dt)
end
Przy kroku czasowym 0.2 otrzymujemy następujący wynik w konsoli:
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() jest nadal wywoływane 60 razy na sekundę, ale wartość dt się zmienia. Widzimy, że tylko 1/5 wywołań update() będzie miało dt równy 1/60, czyli odpowiadający 60 FPS, a reszta będzie równa zero. Wszystkie symulacje fizyki również będą aktualizowane zgodnie z tym dt i będą postępować tylko w co piątej klatce.
Możesz użyć funkcji kroku czasowego kolekcji, aby wstrzymać grę, na przykład podczas wyświetlania popupu albo gdy okno straci fokus. Użyj msg.post("#myproxy", "set_time_step", {factor = 0, mode = 0}), aby wstrzymać, oraz msg.post("#myproxy", "set_time_step", {factor = 1, mode = 1}), aby wznowić.
Więcej szczegółów znajdziesz w set_time_step.