Skrypty

Wprowadzenie

Przed wersją 3.0 Godota, Podstawy GDScript był jedynym językiem, którego można było użyć do oskryptowania gry. Obecnie Godot wspiera cztery (tak, cztery!) języki, a także możliwość dynamicznego dodawania innych języków skryptowych!

To wspaniałe, głównie ze względu na dużą elastyczność, jednak im więcej języków, tym więcej pracy trzeba włożyć w ich utrzymanie.

"Domyślnymi" językami dla Godota są GDScript i VisualScript - są funkcjonalne, wydajne i oferują dobrą integrację z edytorem. Jeśli jesteś wielkim fanem statycznie typowanych języków, możesz użyć C++ lub C#, jednak konieczne jest użycie zewnętrznego IDE.

GDScript

GDScript jest, jak wspomniano powyżej, domyślnym językiem dla Godota, głównie ze względu na wysoki stopień integracji z programem. Ma kilka zalet nad innymi językami:

  • Jest prosta, elegancka i zaprojektowana tak, aby być przypominała, konstrukcję innych języków, użytkownikom, takich jak Lua, Python, Squirrel, itp.

  • Szybko się ładuje i kompiluje.

  • Integracja edytora, pokazuje przyjemność z jaką można z nim pracować, z uzupełnianiem kodu dla węzłów, sygnałów i wielu innych elementów związanych z edytowaną sceną.

  • Ma wbudowane typy wektorowe (takie jak wektory, transformacje itp.), co czyni go wydajnym do intensywnego wykorzystania algebry liniowej.

  • Wspiera wielowątkowość równie wydajnie jak języki silnie typowalne - jedno z ograniczeń, które sprawiło, że unikamy maszyn wirtualnych takich jak Lua, Squirrel, itd.

  • Nie używa kolektora śmieci, więc jest jedynie lekko zautomatyzowany (większość obiektów i tak jest liczona jako odniesienie), przez determinizm.

  • Jego dynamiczny charakter ułatwia optymalizację sekcji kodu w C++ (poprzez GDNative), jeśli wymagana jest większa wydajność, bez konieczności ponownego kompilowania silnika.

Jeśli jesteś niezdecydowany i masz doświadczenie w programowaniu, szczególnie dynamicznie typowanych języków, wybierz GDScript!

VisualScript

Począwszy od wersji 3.0, Godot oferuje Wizualne programowanie. Jest to typowa implementacja języka "bloków i połączeń", ale zaadaptowana do tego, jak działa Godot.

Wizualne programowanie jest doskonałym narzędziem dla nie programistów, a nawet dla doświadczonych programistów, którzy chcą uczynić części kodu bardziej dostępnymi dla innych, takich jak projektanci gier czy artyści.

Może być również używany przez programistów do budowania maszyn stanu lub niestandardowych wizualnych węzłów - na przykład systemu dialogowego.

.NET / C#

Jako że C# Microsoftu jest faworytem wśród twórców gier, dodaliśmy oficjalne wsparcie dla niego. C# jest dojrzałym językiem z mnóstwem kodu napisanego w nim, a wsparcie zostało dodane dzięki hojnej darowiźnie od Microsoftu.

Charakteryzuje się doskonałym kompromisem między wydajnością a łatwością obsługi, choć trzeba mieć świadomość, że posiada oczyszczacz pamięci.

Odkąd Godot używa `Mono <https://mono-project.com>``_ .NET, w teorii można używać dowolnej biblioteki lub frameworka .NET, jak również dowolnego języka programowania zgodnego z Common Language Infrastructure, takiego jak F#, Boo lub ClojureCLR. W praktyce jednak C# jest jedyną oficjalnie obsługiwaną opcją .NET.

GDNative / C++

Wreszcie, jeden z naszych najjaśniejszych dodatków do wydania 3.0: GDNative umożliwia pisanie skryptów w C++ bez konieczności rekompilowania (a nawet restartu) Godota.

Można używać każdej wersji C++, a dzięki zastosowaniu wewnętrznego mostu C API Bridge doskonale działa mieszanie kompilatorów i wersji dla generowanych bibliotek współdzielonych.

Ten język jest najlepszym wyborem pod względem wydajności i co istotne nie musi być używany do napisania całej gry, ponieważ inne części mogą być napisane w GDScript lub skrypcie wizualnym (Visual Script). API jest jednak jasne i łatwe w użyciu, ponieważ przypomina rzeczywiste API C++ Godota.

Poprzez interfejs GDNative można udostępnić więcej języków, ale pamiętajmy, że nie mamy dla nich oficjalnego wsparcia.

Tworzenie skryptu dla sceny

Na resztę tego samouczka tworzymy scenę GUI składającą się z przycisku(button) i etykiety(label), gdzie naciśnięcie przycisku spowoduje aktualizację etykiety. Tak się to demonstruje:

  • Pisanie skryptu i dołączanie go do węzła.

  • Odtwarzanie elementów interfejsu użytkownika za pomocą sygnałów.

  • Pisanie skryptu umożliwiającego dostęp do innych węzłów sceny.

Zanim przejdziesz dalej, przeczytaj dokument o GDScript. Tekst nie jest długi, a język jest dość prosty, więc zorientowanie się w nim zajmie co najwyżej kilka minut.

Konfiguracja sceny

Jeśli masz otworzony projekt "instancje" z poprzedniego samouczka, to zamknij go (Projekt -> Wyjdź do listy projektów) i stwórz nowy projekt.

Użyj przycisku "Dodaj węzeł" (ikona w kształcie plusa) dostępnego na karcie Scena (lub naciśnij Ctrl + A), aby utworzyć hierarchię z następującymi węzłami:

  • Panel

    • Label

    • Przycisk

Drzewo sceny powinno tak wyglądać:

../../_images/scripting_scene_tree.png

Edytor 2D służy do pozycjonowania i zmiany rozmiaru przycisków i etykiet tak, aby wyglądały jak obrazek poniżej. Tekst można ustawić w zakładce Inspektor.

../../_images/label_button_example.png

Na koniec zapisz scenę o nazwie sayhello.tscn.

Dodawanie skryptu

Kliknij prawym przyciskiem myszy na węzeł Panel, a następnie wybierz z menu kontekstowego opcję "Dołącz skrypt":

../../_images/add_script.png

Pojawi się okno dialogowe tworzenia skryptu. To okno dialogowe umożliwia ustawienie języka skryptu, nazwy klasy i innych opcji.

W GDScript to plik reprezentuje klasę, więc pole nazwy klasy nie jest edytowalne.

Węzeł, do którego dołączamy skrypt, jest typu Panel, więc pole dziedziczenia zostanie automatycznie wypełnione przyciskiem "Panel". Tego właśnie chcemy, ponieważ celem skryptu jest rozszerzenie funkcjonalności naszego węzła.

Na koniec wprowadź ścieżkę dla skryptu i wybierz Utwórz:

../../_images/script_create.png

Skrypt zostanie utworzony i dodany do węzła. Możesz to zobaczyć jako ikonę "Otwórz skrypt" obok węzła w zakładce Scena, jak również we właściwościach skryptu pod Inspektorem:

../../_images/script_added.png

Aby edytować skrypt, wybierz jeden z tych przycisków, które są podświetlone na powyższym obrazku. Spowoduje to przeniesienie użytkownika do edytora skryptów, gdzie zostanie dołączony domyślny szablon:

../../_images/script_template.png

Niewiele jest tam do zrobienia. Funkcja ready() jest wywoływana, gdy węzeł i wszystkie jego dzieci wejdą w aktywną scenę. Wyjaśnienie: _ready() nie jest konstruktorem; zamiast tego konstruktorem jest _init().

Rola skryptu

Skrypt dodaje zachowanie do węzła. Służy do kontrolowania sposobu działania węzła oraz jego interakcji z innymi węzłami: dziećmi, rodzicami, rodzeństwem itd. Lokalnym zakresem skryptu jest węzeł. Innymi słowy, skrypt dziedziczy funkcje tego węzła.

../../_images/brainslug.jpg

Obsługa sygnału

Sygnały są "emitowane" w momencie wystąpienia określonego rodzaju akcji i można je podłączyć do dowolnej funkcji dowolnej instancji skryptu. Sygnały są używane głównie w węzłach GUI, choć inne węzły również je posiadają, a w własnych skryptach można nawet definiować własne sygnały.

W tym kroku sygnał "wciśnięty" zostanie podłączony do funkcji niestandardowej. Tworzenie połączeń jest pierwszą częścią, a definiowanie funkcji niestandardowych drugą częścią. W pierwszej części, Godot przewiduje dwa sposoby tworzenia połączeń: poprzez wizualny interfejs edytora lub poprzez kod.

Podczas wykorzystywania metody w kodzie, dla przypomnienia przesłońmy to w jaki sposób działa edytor interfejsu dla dalszych postępów.

Zaznacz węzeł "Przycisk" na drzewie scen, a następnie wybierz kartę "Węzeł". Następnie upewnij się, że wybrano opcję "Sygnały".

../../_images/signals.png

Jeśli wybierzesz "wciśnij()"(pressed()) pod "BaseButton" i klikniesz przycisk "Connect..." w prawym dolnym rogu, otworzysz okno dialogowe tworzenia połączenia.

../../_images/connect_dialogue.png

Na górze okna wyświetlona jest lista węzłów Twojej sceny z nazwą węzła emitującego podświetlonego na niebiesko. Zaznacz tutaj węzeł "Panel".

Dół okna dialogowego wyświetla nazwę metody, która zostanie stworzona. Domyślnie nazwa metody będzie zawierała nazwę węzła emitującego ("Przycisk" w tym wypadku), tworząc w rezultacie nazwę:_on_[NazwaWęzłaEmitującego]_[NazwaSygnału].

I na tym kończy się przewodnik, jak korzystać z interfejsu wizualnego. Jest to jednak samouczek skryptowy, więc aby się uczyć, zanurzmy się w podstawy tego procesu zawarte w kodzie!

Aby to osiągnąć, wprowadzimy funkcję, która jest prawdopodobnie najczęściej używana przez programistów Godota: Node.get_node(). Ta funkcja używa ścieżek do pobierania węzłów w dowolnym miejscu sceny, względem węzła, który jest właścicielem skryptu.

Usuńmy wszystko pod extends Panel. Resztę skryptu wypełnimy ręcznie.

Ponieważ Przycisk i Etykieta są rodzeństwem pod panelem, do którego dołączony jest skrypt, można obsłużyć Przycisk wpisując poniżej funkcję _ready():

func _ready():
    get_node("Button")
public override void _Ready()
{
    GetNode("Button");
}

Następnie dodajmy funkcję, która zostanie wywołana po naciśnięciu przycisku:

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
public void _OnButtonPressed()
{
    GetNode<Label>("Label").Text = "HELLO!";
}

Na koniec należy podłączyć przycisk do sygnału "pressed" do _on_Button_pressed() używając Object.connect().

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")
public override void _Ready()
{
    GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
}

Końcowy skrypt powinien wyglądać następująco:

extends Panel

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
using Godot;

// IMPORTANT: the name of the class MUST match the filename exactly.
// this is case sensitive!
public class sayhello : Panel
{
    public override void _Ready()
    {
        GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
    }

    public void _OnButtonPressed()
    {
        GetNode<Label>("Label").Text = "HELLO!";
    }
}

Uruchom scenę i naciśnij przycisk. Powinieneś otrzymać następujący wynik:

../../_images/scripting_hello.png

Witaj! Gratulujemy oskryptowania pierwszej sceny.

Informacja

Popularnym błędem (pomyłką) popełniają podczas tego poradnika jest to, w jaki sposób get_node(path) działa. Dla węzła przekazanego get_node(path) szukanie odbywa się pośród węzłów-dzieci. W powyższym kodzie oznacza to, że Button music być węzłem-dzieckiem od Panel'u. Jeżeli Button byłby natomiast węzłem dzieckiem od Label, wtedy kod musiałby wyglądać tak:

# Not for this case,
# but just in case.
get_node("Label/Button")
// Not for this case,
// but just in case.
GetNode("Label/Button")

Należy pamiętać, że do węzłów odwołuje się poprzez ich nazwę, a nie typ.

Informacja

Panel, znajdujący się po prawej stronie okna połączeń służy do wiązania określonych wartości do parametrów połączonych funkcji. Możesz dodawać i usuwać wartości różnych typów.

Podejście z użyciem kodu również pozwala na takie przypisania poprzez użycie czwartego parametru, Array, którego wartość domyślnie jest pusta. Możesz dowiedzieć się więcej na ten temat, czytając o metodzie Object.connect.