Funkcje 2.3+ i ich zasięgi

Poniedziałek, 28 Czerwca 2021, 17:55
Czas czytania 5 minut, 41 sekund
Zgodne z GM: gms2
W GMS 2.3+ zniknęły skrypty, a w ich miejsce pojawiły się funkcje. Zależnie o tego, gdzie i jak zostaną zdefiniowane, mogą wpływać na inny zakres zasobów lub gry, dlatego w tym artykule wytłumaczę czego można się po GMS2 spodziewać.
W GMS 2.3+ zniknęły skrypty, a w ich miejsce pojawiły się funkcje. Skrypty są teraz jedynie grupami na jedną lub więcej funkcji i dla wstecznej kompatybilności, importując stary projekt, każda funkcja trafia do skryptu o tej samej nazwie, tworząc nowy skrypt domyślnie dostajemy też pustą funkcję o tej samej nazwie jako gotowy kod.

Funkcje stworzone w skryptach mają globalny zasięg (jak do tej pory), pojawiła się jednak funkcja tworzenia funkcji w obiektach. Jakby tego było mało, można też tworzyć funkcje anonimowe, przypisane do zmiennej. W trakcie działania programu nie tak prosto je odróżnić i trzeba pamiętać co zostało jak zdefiniowane, gdyż można łatwo wpaść na błąd programu ze względu na to, co dla danej funkcji kryje się pod słowem kluczowym self.

Funkcja nazwane:
kodfunction nazwana() {}
function nazwana(parametr, inny) {}

Funkcje anonimowe/lambda:
kodlambda = function() {}
lambda = function(parametr, kolejny) {}

Oba rodzaje funkcji wywołujemy korzystając z nazwy, do której jej przypisano + nawiasu (np. nazwana() lub lambda() ).

Zasięg funkcji:W GMS 2.3+ wszystko co definiujemy w skryptach, trafia do przestrzeni globalnej (global. ), ale dodatkowo, funkcje nazwane zdefiniowane w skryptach, trafiają do osobnej puli, tej samej co funkcje wbudowane, nazwijmy je superfunkcjami. Nie są one współdzielone referencją, więc nie da się nadpisać superfunkcji, nie da się też w obiektach używać zmiennych o tej nazwie (poza zmienną tymczasową, o ile nie zostanie użyta jako funkcja - wtedy superfunkcja ma priorytet).

Zgodnie z tymi informacjami, superfunkcje są już zdefiniowane w momencie, gdy GMS zaczyna przetwarzać skrypty i można ich używać (można też założyć, że ich definicje z tego skryptu zostały usunięte), natomiast nie dotyczy to funkcji anonimowych, które są dostępne dopiero po wykonaniu się linijki kodu która je definiuje.
Ponieważ w GMS 2.3 kolejność zasobów może być losowa (inna niż w drzewku zasobów), warto mieć to na uwadze - globalne funkcje anonimowe powinno się używać jedynie w skrypcie w którym są zdefiniowane, lub w funkcjach i obiektach które zostaną użyte po starcie gry - nie powinno się do nich odnosić w innych skryptach bezpośrednio w globalnym zasięgu.
kod// globalne funkcje nazwane - kolejność
// obie wersje są poprawne:
globalna();
function globalna() {}

//lub:
function globalna() {}
globalna();

// globalne funkcje lambda
// nieprawidłowo
lambda(); // - jeszcze nie istnieje
lambda = function() {}

// prawidłowo
lambda = function() {}
lambda();

// odwołanie do funkcji jest możliwe poprzez
globalna();
global.globalna(); // nie musi być to ta sama funkcja co wyżej, jeśli została nadpisana
global.lambda();

Wioczność i przeciążanie funkcjiFunkcja nazwane będą dostępne w zasięgu, w jakim zostały stworzone.

Funkcje stworzone w skrypcie:
- nazwane: są widoczne tak jak funkcje wbudowane są superglobalne, dodatkowo tworzona jest kopia (nie referencja!) pod słowem global. i traktowana będzie ona jak funkcja anonimowa
- anonimowe: są widoczne po prefiksie global.
Funkcje stworzone w obiekcie:
- nazwane/anonimowe: są widoczne w tym obiekcie, tak jak każda inna zmienna

Jeżeli funkcja definiuje kolejną, to jej widoczność znów zależy od miejsca, w którym została stworzona. Przykład takiej funkcji:
kodfunction a() {
function b() {}
c = function() {}
}

Funkcja nazwana stworzona przez inną funkcję w skrypcie:
- b i c nie będzie istnieć, bez wywołania a()
- jeśli została wywołana, to zarówno funkcja nazwana b jak i anonimowa c w skrypcie będzie widoczna pod swoją nazwą, oraz trafi do przestrzeni global. pozostając widoczną w innych zasobach
Funkcja nazwana stworzona przez inną funkcję w obiekcie:
- po wywołaniu a(), pojawią się w obiekcie zmienne b i c z funkcjami. Jeżeli istnieją takie same funkcje w przestrzeni global (globalvar), nie zostaną nadpisane.

Superfunkcji nie da się nadpisać, ale można nadpisać jej wersję pod zmienną globalną. Prowadzi to do dziwnej postaci, w której a() i global.a() mogą być różne.

Kod z funkcji i jego wpływ na grę zależnie od zasięgu:Superfunkcja zmienia wartości zmiennych w zasięgu, w którym jest wywołana, oznacza to, że:
kodfunction a() { value = 5; }- wywołane a() skrypcie, ustawi global.value = 5;
- wywołanie a() obiekcie, ustawi lokalną zmienną value = 5;
- wywołanie global.a() w obiekcie - tak samo jak dla aninimowej

Funkcja anonimowa zmieni wartość zmiennych w zasięgu, w którym została stworzona, oznacza to, że:
koda = function() { value = 5; }- wywołanie a() w skrypcie, lub global.a() w obiekcie, ustawi global.value = 5;

Zmiana zasięgu:

Zasięg superfunkcji zmienia się za pomocą with() - tak samo jak do tej pory.

Funkcja zdefiniowana w obiekcie, działa trochę podobnie do zmiennych tymczasowych, tzn. nie wymaga użycia other., ale wykona się w kontekście wybranego obiektu, np.:
kod// w object0
function test() { show_debug_message(object_get_name(self.object_index)); }

test(); // object0
with (object1) { test(); } // object1
with (object1) { other.test(); } // object0
jak widać, kontekst wykonania nadaje with, a nie pochodzenie funkcji.

Wszystko zmienia się jednak, gdy mówimy o funkcji anonimowej - wtedy zasady są takie same, jak używania innych zmiennych razem z with, a kontekst pozostanie taki, jak w momencie utworzenia funkcji:
kod
// w object0
test = function() { show_debug_message(object_get_name(self.object_index)); }

test(); // object0
with(object1) { test(); } // zwraca błąd, bo object1 nie ma zmiennej test
with(object1) { other.test(); } // object0

Aby zmienić kontekst funkcji anonimowej, można skorzystać z funkcji method():
kod// w object0
test = function() { show_debug_message(object_get_name(self.object_index)); }

_test = method(object1, test); // tworzy kopię funkcji "test" ale ustawia nowy kontekst
_test(); // object1
with(object1) { _test(); } // zwraca błąd, bo object1 nie ma zmiennej test
with(object1) { other._test(); } // object1
jeśli jednak skorzystamy z var, zasady się zmieniają:
kodvar _tmp = method(object1, test); // tworzy kopię funkcji "test" ale ustawia nowy kontekst
_tmp (); // object1
with(object1) { _tmp (); } // object1
with(object1) { other._tmp (); } // zwraca błąd, bo dla zmiennej tymczasowej other to object1, który nie ma zmiennej _tmp
Można sobie wyobrazić, że var+with powoduje, że niewidzialne "other." pojawia się przed nazwą naszej tymczasowej zmiennej, stąd odwrócenie sytuacji.

Użycie undefined jako nowego kontekstu:
- w przypadku zwykłej zmiennej, zachowa się tak samo, jak funkcja przed zmianą kontekstu
- w przypadku zmiennej tymczasowej, weźmie kontekst z with()

Użycie global jako nowego kontekstu spowoduje błąd - ale tylko dla tej konkretnej funkcji, bowiem global nie ma właściwości object_index. Poza tym, użycie global jest jak najbardziej możliwe i prawidłowe.
Komentarze (łącznie 0):
Nie ma jeszcze żadnego komentarza. Czas to zmienić

Najnowsze wersje GameMakera:

Stabilna
2024.2.0.132 • 2024.2.0.163
wydana 45 dni temu
LTS
2022.0.2.51 • 2022.0.2.49
wydana 184 dni temu
Beta
2024.400.0.543 • 2024.400.0.562
wydana  wczoraj
= IDE, = Runtime
Użytkownicy online
1 użytkownik aktywny:
gości: 1,
(~ostatnie 15 minut)
Discord
11 użytkowników online na discordzie:
DungeonFairy🧚, Carl-bot, GibkiKaktus, Kowu, antek, Dyno, 𝕳𝖚𝖌𝖔 𝕲𝖔𝖓𝖝𝖆𝖑𝖊𝖝, LeD, bagno, l..., Draczeq
Shoutbox
gnysek (20:44, 11.04.24)
Niektórzy dlatego wybierają GMEdit. Ale ja liczę na Code Editor 2, tylko na razie zbyt zbugowany jest.
Tymon (16:11, 11.04.24)
Stitch dla mnie osobiście jest lepszy bo nie musze kopać się z interfejsem GMa i mogę tylko pisać kod.
Tymon (16:05, 11.04.24)
Yes. Obecny nie jest taki zły, jak zainstalowałem najnowszą stabilną to w porównaniu z tym czego używałem... 10 lat temu...? Wszystko wydaje się lepsze.
gnysek (22:48, 10.04.24)
bscotch/stitch ? Ja czekam na fixy do nowego edytora, bo wszystko wydaje się dziś lepsze od tego obecnego :D
Tymon (19:54, 10.04.24)
Hm, Stitch okazuje się całkiem dobrą alternatywą dla wbudowanego edytora
Wojo (22:16, 08.04.24)
siemano huder myślałem, że zniknąłeś całkiem z gmclanu bo na discordzie cie nie ma :D
I am Lord (00:37, 05.04.24)
O dzięki :D
gnysek (09:58, 02.04.24)
Znalazłem na podstawie jego postów: youtube.com/@Jakim_
I am Lord (20:16, 01.04.24)
Ktoś ogarnia jakie konto miał Jakim na YT?
gnysek (16:07, 29.03.24)
Nowy Edytor kodu jednak po świętach
Starsze wpisy znajdziesz w Archiwum.
Ankieta
Ile zarobiłeś do tej pory na grach stworzonych w GM?