Skryptowanie

Wprowadzenie

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

To świetne, głównie ze względu na dużą elastyczność jaką to daje, jednak to czyni naszą pracę dla wsparcia języków trudniejszą.

"Głównymi" językami w Godocie są GDScript i VisualScript. Głównym powodem, by je wybrać jest ich poziom integracji z Godotem, gdyż czyni to doświadczenie płynniejszym; oba mają zgrabną integrację z edytorem, podczas gdy C# i C++ muszą być edytowane w oddzielnym IDE. Jeśli jesteś wielkim fanem statycznie typowanych języków, użyj zamiast tego C# i C++.

GDScript

GDScript jest, jak wspomniane powyżej, głównym językiem używanym w Godocie. Ma kilka zalet nad innymi językami, dzięki swojej silnej integracji z Godotem:

  • Jest prosty, elegancki i zaprojektowany tak, aby był znajomy dla użytkowników innych języków, takich jak Lua, Python, Squirrel itp.

  • Wczytuje się i kompiluje niesamowicie szybko.

  • Integracja edytora daje przyjemność pracy, oferując podpowiadanie kody dla węzłów, sygnałów i wielu innych rzeczy odnoszących się do edytowanej sceny.

  • 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 statycznie typowane - jedno z ograniczeń, które sprawiło, że unikamy maszyn wirtualnych takich jak Lua, Squirrel itp.

  • Nie używa odśmiecacza pamięci, więc poświęca trochę automatyzacji (większość obiektów i tak ma zliczane odwołania) na rzecz determinizmu.

  • 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 systemów opartych na wizualnych węzłach - 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.