31 marca 2025

Reusable enter-exit component

W każdej grze opartej o odwiedzanie zbudowanych (lub wygenerowanych) poziomów musimy uwzględnić możliwość ich przełączania. Stąd bardzo szybko pojawia się potrzeba stworzenia mechaniki, która to umożliwia.
W ramach  Godot używamy do tego prostego polecenia wbudowanego w silnik, które przełączy nam scenę, w której jest jesteśmy na scenę docelową. Jest to ChangeSceneToPacked, poniżej sposób użycia:

 GetTree().ChangeSceneToPacked(ResourceLoader.Load<PackedScene>(TargetScene));

Parametr  TargetScene to ścieżka do docelowej sceny w ramach naszego projektu, przykładowo:

string TargetScene = "res://scenes/levels/World.tscn";

Użycie takiej konstrukcji powoduje przełączenie aktualnej sceny na docelową i usadowienie postaci w miejscu, w którym umieściliśmy ją w edytorze Godota podczas tworzenia załadowanego poziomu. I w najprostszym przypadku jest to wystarczające rozwiązanie. 

Kłopot pojawia się w momencie gdy na docelowej scenie znajduje się kilka punków gdzie może się pojawić gracz i kilka punktów, z których może przejść do innych scen. Rozwiązanie podane powyżej nie umożliwia wykonanie takiej czynności. 

W efekcie potrzebujemy odpowiednio zaprogramowanego, reużywalnego węzła, który uprości tworzenie nowych wejść-wyjść pomiędzy poziomami wraz z ustawieniem gracza w interesującym nas miejscu.

A poniżej (moje) rozwiązanie 

Na początek musimy się zastanowić czego w ogóle potrzebujemy, aby zabawki nam działały.
Zgrubnie

- mechanizmu przełączania ekranów możliwego do używania na każdej scenie (czyli jakiegoś węzła)
- mechanizm musi być konfigurowalny z poziomu godota (eksport parametrów)
- miejsca gdzie zapamiętujemy gdzie mamy wylądować na docelowej scenie (globalna klasa)
- obsługi ustawienia postaci na uruchamianej scenie w docelowym miejscu (to już per scena)
- obsługa powinna być przyjemna dla oka stąd potrzeba stworzenia jakiego efektu przejścia między scenami i może nawet okraszonego dźwiękiem

Punkt 1 - Reużywalny komponent (ku pamięci - kod piszę w c#)

Bazą sceny przełączającej jest węzeł Area2D, ponieważ jest to płaski obszar o niemal dowolnym kształcie możliwy do dodania do drzewa w interesującej nas scenie. Musi wykrywać kolizję z postacią gracza i reagować na nią poprzez użycie wbudowanych w Area2D sygnałów i najważniejszego w takim momencie body_entered(body:Node2D)

Widoczny na zrzucie węzeł o nazwie LevelExit to nasz nazwany Area2d, węzeł ExitArea to standardowy CollisionShape2D wymagany w połączeniu Area2D.  Widoczny w drzewie poniżej FadeScreen jest kolejnym reużywalnym komponentem, który doda je nam efekt łagodnego przejścia między ekranami. Jego konstrukcję podam dalej. 


a tutaj definicja wykorzystanego sygnału

Na razie żadne cuda się tu nie dzieję. W edytorze mamy zdefiniowany kształt obszaru kolizyjnego i nic więcej nie potrzeba


Ustaliliśmy wcześniej, że obszar wyjścia-wejścia do scen musi być konfigurowalny, aby można go było używać pomiędzy scenami i nie lepić kodu per kod sceny. 


Jak widać w definicji klasy opisującej komponent pojawiły się cztery samo-komentujące ;-) się pola.
Jeśli jednak ich opisy nie są jasne:
Pola obowiązkowe :) 
Target Position to miejsce w postaci kordynatów X,Y gdzie na docelowej scenie ma się pojawić bohater. Typ: Vector2
Target Scene to scena, która ma się otworzyć po uruchomieniu danego komponentu wejścia-wyjścia. Typ: string
Source Exit to id naszego wejścia-wyjścia potrzebne do ustalenia, które z nich zostało użyte. Typ: string

Pole nieobowiązkowe:
Transport Sound - jak nazwa wskazuje to dźwięk jaki ma wydać teleportacja. Na razie pole nie jest używane w moim kodzie. Typ: string który ma wskazywać link do zasobu w assetach gry.

A poniżej węzeł w drzewie sceny: 

Oraz jego konfiguracja:

i jak wygląda na mapce (Tak - to ten plusik z tłem powyżej drzwi) 



Ale diabeł tkwi nie w zwykłym lepieniu węzłów w Godot, ale w kodzie który to obsługuje.
A o tym będzie kolejny wpis ;-)