Skrypty

Wprowadzenie

Przed wersją 3.0 Godota, doc_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 typowane statycznie - jest to jedno z ograniczeń, przez które unikamy maszyn wirtualnych, 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 dla wydajności i nie musi być używany przez całą grę, ponieważ inne części mogą być napisane w GDScript lub skrypcie wizualnym. 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

Użyj okna dialogowego „Dodaj węzeł - dziecko” 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.

Mimo że będziemy tworzyć nasze połączenia poprzez kod przez resztę tego samouczka, na przyszłość przyjrzyjmy się jak dodać połączenie, korzystając z interfejsu edytora.

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

W lewym dolnym rogu znajdują się kluczowe elementy potrzebne do utworzenia połączenia: węzeł, który implementuje metodę (reprezentowany tutaj jako NodePath) oraz nazwa metody, którą chcesz wykonać.

W lewym górnym rogu wyświetlana jest lista węzłów sceny, a nazwa węzła emitującego jest podświetlona na czerwono. Wybierz tutaj węzeł „Panel”. Po wybraniu węzła, ścieżka NodePath na dole zostanie automatycznie zaktualizowana, aby wskazać ścieżkę względną od węzła emitującego do wybranego węzła.

By default, the method name will contain the emitting node’s name („Button” in this case), resulting in _on_[EmitterNode]_[signal_name]. If you do have the „Make Function” check button checked, then the editor will generate the function for you before setting up the connection.

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.

Dla wygody usuwa wszystko pod rozszerza Panel. Resztę skryptu wypełnisz ręcznie.

Ponieważ Przycisk i Etykieta są spokrewnione w panelu, do którego dołączony jest skrypt, możesz przywołać Przycisk wpisując poniższe zdanie poniżej funkcji ready():

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

Następnie należy zapisać 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!";
}

Finally, connect the button’s „pressed” signal to _ready() by using 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 scenariusz powinien tak wyglądać:

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

A common misunderstanding regarding this tutorial is how get_node(path) works. For a given node, get_node(path) searches its immediate children. In the above code, this means that Button must be a child of Panel. If Button were instead a child of Label, the code to obtain it would be:

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

Pamiętaj, że do referencji danego węzła odnosimy się po jego nazwie, nie typie.

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.