GM 2023+: Singleton w GM

Poniedziałek, 13 Lutego 2023, 23:52
Czas czytania 3 minuty, 23 sekundy
Zgodne z GM: gms2
GM 2023 wprowadza nową składnię, która pozwala pobierać statyczne wartości konstruktorów za pomocą prostszej składni.
GameMaker w wersjach 2023+ (od 2023.1) wprowadza nowe funkcje - static_get() i static_set(), które pozwalają pobrać "statyczną" część funkcji, struktur i konstruktorów, lub nadpisać tę przypisaną do jakiegoś obiektu.

Wskazówka:
Zwykła struktura domyślnie nie ma statycznej części, jedynie te utworzone przez = new nazwa_konstruktora();, lub takie, na których użyto static_set()

Ot, załóżmy, że mamy taki kod:

kodfunction add_points(_score = 0) {
static points = 0;
points = points + _score;
return points;
}

Dzięki zastosowaniu "static", zmienna "score" jest na stałe przypisana do funkcji "add_score" i nie znika pomiędzy jej wywołaniami (wszystkie inne zmienne, jeśli nie są poprzedzone var, będą odczytywać/zapisywać zmienną o danej nazwie w obecnym kontekście, najczęściej w obiekcie).

Takie statyczne, są tak naprawdę strukturą "ukrytą" w zakamarkach GMa (mona założyć, że funkcja/struktura sprawdzając swoje zmienne, najpierw sprawdza, czy ma swoją lokalną wersję, potem czy ma statyczną, a dopiero gdy nie znajdzie obu rzuca błędem o nieznanej zmiennej) i funkcja static_get pozwala nam dostać bezpośrednią referencję do tej normalnie ukrytej struktury. Możemy wtedy zmienić jej wartości spoza danej funkcji, czy nawet dodać/usunąć wartości. Dzięki static_set możemy je nawet podmienić - i coś, co było wcześniej instancją jednej klasy, nagle stanie się instancją innej.

Twócy GMa postanowili, że pozwolą się dobrać się do tej struktury w jeszcze prostszy sposób, dzięki czemu dostaliśmy w GMie

Singleton
W przypadku funkcji, które zawierają jakiś static, jeśli te statyczne wartości zostały zainicjowane pierwszy raz, możemy pisać teraz:
kodnazwa_funkcji.wartosc;
Wskazówka:
W momencie kompilacji, GM widząc nazwa_funkcji.cokolwiek, przerabia kod na static_get(nazwa_funkcji).cokolwiek

W ten sposób można odnosić się czy do funkcji, czy do konstruktorów - trzeba jednak pamiętać, aby chociaż raz je zainicjować.

kodenum diff {
easy, medium, hadrd
}

function Game() constructor {
static difficulty = diff.easy;
static points = 0;
static hp = 100;
}

Game(); // inicjalizacja pierwszy raz, może być w globalnym skrypcie, zaraz za definicją
show_debug_message(Game.hp); // zwraca: 100

Uwaga!
Warto jednak pamiętać, że skoro tak naprawdę używamy "static_get", dostając strukturę która zawiera nasze statyczne dane, wykonując funkcje z tej struktury, ich kontekst wykonania zmienia się, na obecny (bo wyciągamy funkcję na zewnątrz i tam uruchamiamy). Wszelkie zmienne nadpiszą więc te w obecnym kontekście (globalny, instancja), a nie te w tej strukturze!

Co to oznacza? Załóżmy, że dodamy do naszego konstruktora funkcję "leczącą":
kodfunction Game() constructor {
static hp = 10;

// nowa funkcja
static heal = function() {
hp = 100; // ! tu kryje się błąd !
}
}

Pisząc

kodGame.heal();
Wyobraźmy sobie, że tak naprawdę napisaliśmy:

kodvar a = static_get(Game).heal; // dostajemy referencję na funkcję, nie całą strukturę
a(); // odpala się w obecnym kontekście, nie wewnątrz struktury static_get(Game)

Wskazówka:
Wbrew pozorom, nie wykonamy with(static_get(Game)) {hp = 100;} - co jest prawidłową składnią GMową i wykonałoby się w kontekście struktury statycznej. Jest prostsza opcja.

Funkcja "heal" wykona się więc w obecnym kontekście - jeśli jest to skrypt (poza funkcjami), to ustawimy zmienną global.hp = 100;. Jeśli instancja, to jej zmienna "hp" ustali się na 100 (jeśli instancja tej zmiennej nie miała - no to już ją ma...).

Od wersji 2023.1 GameMaker pozwala już jednak zmieniać wartości używając podobnej składni:

kodfunction Game() constructor {
static hp = 10;

static heal = function() {
Game.hp = 100; // można by też napisać static_get(Game).hp = 100;
}
}

Game();

show_debug_message(Game.hp); // zwróci 10
Game.heal();
show_debug_message(Game.hp); // zwróci 100

Grafika: /upload/ajax/20230213_9377dd8f120eeddc57c2ab4fc79b1a45.png
Komentarze (łącznie 2):
gnysek (Wto., 14 Lut. 23, 11:56)
#1

Russell potwierdził na Discordzie, że brak opcji zapisu (np. Game.hp = 100) to bug i w 2023.2 powinni to naprawić - do tego jednak czasu nie aktualizuję artykułu :)

gnysek (Pon., 27 Lut. 23, 17:30)
#2

Ok, sprawdziłem, w wersji 2023.2 jest to już naprawione i można pisać "Game.hp = <cos>".

Najnowsze wersje GameMakera:

Stabilna
2024.13.0.190 • 2024.13.0.238
wydana  3 dni temu
LTS
2022.0.3.85 • 2022.0.3.99
wydana 129 dni temu
Beta
2024.1300.0.785 •
2024.1300.0.790
 0.16.1

wydana 15 dni temu
= IDE, = Runtime, = GMRT
Użytkownicy online
2 użytkowników aktywnych:
gości: 1, userów: 1
 Adriann
(~ostatnie 15 minut)
Discord
43 użytkownicy online na discordzie:
Alice, LeD, Nitro Slav, Tymon, Carl-bot, lethian, Wielki Druid, Kysiu, Kowu, Kuzyn, OdrzuconyKrakers, fervi, 𝕳𝖚𝖌𝖔 𝕲𝖔𝖓𝖝𝖆𝖑𝖊𝖝, m..., 42traviss, r..., Threef, Uzjel, 🧁Cupcake🧁, antek, firemark, yazaa, Dyno, 🆅🅸🆃🅾74🅼, Deusald, szmalu, ZYGZAK, LadyLush, Marco, 21Lancz, bagno, Tidżi, Mtax, g..., Sporek, Kandif, l..., Cebul, Borek, s..., Add92, h..., Shockah
Shoutbox
gnysek (13:44, 10.04.25)
Za 3-4 miesiące GM przejdzie na wydania "półroczne", więc korzystanie z wersji beta żeby sprawdzić nowości będzie wskazane :P
Adriann (18:09, 08.04.25)
Odpowiadam, dzisiaj :D
Adriann (20:48, 04.04.25)
A kiedy te UI layery mają wejść do normalnej wersji gma?
gnysek (00:38, 11.03.25)
I jak, zobaczyłeś ? :D Trochę im zjechało na publiczny release, ale były już w ostatnich dniach lutego dostępne jak się wie, jak pobrać kandydatów do bety :P
Kuzyn (21:30, 05.03.25)
uwierzę jak zobaczę :P
gnysek (10:35, 18.02.25)
W ciągu 10 dni mają wyjść w końcu Layery UI :D
Wojo (10:25, 27.12.24)
Jak tworzyłeś* ah ta niecną autokorekta (kiedyś też stworzyłem apki na androida w sumie)
Wojo (10:23, 27.12.24)
O siemka baca, czasami myślę o tobie w kontekście tego jak tworzyłem apki na androida. Swoją drogą czasami zapominam, że forum istnieje bo cały ruch teraz utrzymuje się na discordzie, ale pora to zmienić!
Uzjel (20:17, 10.12.24)
Cały ruch przeniósł się na Discorda.
MagnusArias (17:43, 01.12.24)
O matko... a ja tutaj jestem od ponad 15 lat i czasami zaglądam... biernie bo biernie, ale czasem wpadnę
Starsze wpisy znajdziesz w Archiwum.
Ankieta
Ile zarobiłeś do tej pory na grach stworzonych w GM?