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.06.2.162 • 2024.6.1.208
wydana 12 dni temu
LTS
2022.0.2.51 • 2022.0.2.49
wydana 284 dni temu
Beta
2024.800.0.597 •
2024.800.0.620
 0.11.0

wydana  2 dni temu
= IDE, = Runtime, = GMRT
Użytkownicy online
1 użytkownik aktywny:
gości: 1,
(~ostatnie 15 minut)
Discord
Shoutbox
gnysek (18:31, 25.07.24)
Ogłaszam nowy etap w historii GameMakera.
gnysek (11:36, 08.07.24)
Ale w sumie taki numer GG był bezpieczniejszy niż nr. telefonu czy kontakt społecznościowy. Utrudniał stalkowanie i ułatwiał banowanie.
Wojo (08:08, 08.07.24)
Niestety to już nie te czasy kiedy pytało się kasjerki o wiek i numer Gadu-Gadu...
Adriann (08:28, 05.07.24)
Albo okraść :|
Adriann (08:28, 05.07.24)
Może pani chciała zobaczyć twoje dane i Cię poderwać :d
gnysek (10:38, 03.07.24)
Mnie ostatnio w Żabce zapytali o wiek. A mam już ponad dwie osiemnastki.
Wojo (08:27, 30.06.24)
Ogólnie to miał być żart ponieważ portal internetowy, którego można opisać jako PH jest portalem przeznaczonym dla dorosłych. Miało być śmiesznie wyszło żenująco, a wiadomości w shoutboxie nie mogę skasować :P
Wojo (09:40, 28.06.24)
Tymon jak co wizytę musiałem potwierdzić wiek
gnysek (14:15, 17.06.24)
Bo Łapusz woli alkohol, niż się organizować. Co tam Pixel Heaven, sprawdźcie jego zbiórki na książki...
Adriann (21:02, 13.06.24)
Bardzo słusznie, straszna patola z tą organizacją :D
Starsze wpisy znajdziesz w Archiwum.
Ankieta
Ile zarobiłeś do tej pory na grach stworzonych w GM?