GDScript Grundlagen

Einführung

GDScript ist eine high-level, dynamisch typisierte Programmiersprache zum Erstellen von Inhalten. Es verwendet eine ähnliche Syntax wie Python (Blöcke basieren auf Einrückung und viele Schlüsselwörter sind ähnlich). Es zielt auf eine Optimierung und enge Integration mit der Godot Engine ab, um große Flexibilität bei der Erstellung von Inhalten und deren Integration zu ermöglichen.

Geschichte

Bemerkung

Ältere Artikel über GDScript wurden hierhin verschoben: ref:Frequently Asked Questions <doc_faq_what_is_gdscript>.

Beispiel von GDScript

Manche Leute lernen besser, indem sie einfach die Syntax betrachten, deshalb hier ein Beispiel wie GDScript aussieht.

# A file is a class!

# Inheritance

extends BaseClass

# (optional) class definition with a custom icon

class_name MyClass, "res://path/to/optional/icon.svg"


# Member variables

var a = 5
var s = "Hello"
var arr = [1, 2, 3]
var dict = {"key": "value", 2: 3}
var typed_var: int
var inferred_type := "String"

# Constants

const ANSWER = 42
const THE_NAME = "Charly"

# Enums

enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY}
enum Named {THING_1, THING_2, ANOTHER_THING = -1}

# Built-in vector types

var v2 = Vector2(1, 2)
var v3 = Vector3(1, 2, 3)


# Function

func some_function(param1, param2):
    var local_var = 5

    if param1 < local_var:
        print(param1)
    elif param2 > 5:
        print(param2)
    else:
        print("Fail!")

    for i in range(20):
        print(i)

    while param2 != 0:
        param2 -= 1

    var local_var2 = param1 + 3
    return local_var2


# Functions override functions with the same name on the base/parent class.
# If you still want to call them, use '.' (like 'super' in other languages).

func something(p1, p2):
    .something(p1, p2)


# Inner class

class Something:
    var a = 10


# Constructor

func _init():
    print("Constructed!")
    var lv = Something.new()
    print(lv.a)

Wenn Sie bereits Erfahrung mit statisch typisierten Sprachen wie C, C++ oder C# haben, aber bisher keine dynamisch typisierte verwendet haben, wird das Lesen dieser Anleitung empfohlen: GDScript: Eine Einführung in dynamische Programmiersprachen.

Sprache

Im Folgenden sei ein Überblick über GDScript gegeben. Details, wie welche Methoden es für Arrays oder andere Objekte gibt, sollten in den verlinkten Klassenbeschreibungen nachgeschlagen werden.

Bezeichner

Jede Zeichenkette, die beschränkt ist auf Zeichen des Alphabets (a bis z und A bis Z), Ziffern (0 bis 9) und _, ist ein gültiger Bezeichner. Zusätzlich dürfen Bezeichner nicht mit einer Ziffer beginnen. Bei Bezeichner wird Groß- und Kleinschreibung beachtet (foo unterscheidet sich von FOO).

Schlüsselwörter

Das Folgende ist eine Auflistung Schlüsselwörter, die von der Sprache unterstützt werden. Da Schlüsselwörter reservierte Begriffe (Tokens) sind, können sie nicht als Bezeichner verwendet werden. Operatoren (wie in, not, and oder or) und Namen eingebauter Typen, die in den folgenden Abschnitten aufgelistet werden, sind ebenfalls reserviert.

Schlüsselwörter werden im GDSkript Tokenizer definiert, falls Sie einen Blick unter die Haube werfen möchten.

Schlüsselwort Beschreibung
if Siehe if/else/elif.
elif Siehe if/else/elif.
else Siehe if/else/elif.
for Siehe for.
while Siehe while.
match Siehe match.
break Beendet die Ausführung der aktuellen for oder while Schleife.
continue Springt sofort zur nächsten Iteration der for oder while Schleife.
pass Benutzt man, wo eine Anweisung zwar syntaktisch benötigt wird, aber die Ausführung von Code eigentlich ungewünscht ist, z.B. in leeren Funktionen.
return Gibt einen Wert aus einer Funktion zurück.
class Defines an inner class.
class_name Defines a class name and optional icon for your script.
extends Definiert die Basisklasse, von welcher diese Klasse abgeleitet werden soll.
is Testet, ob eine Variable von einer gegeben Klasse abgeleitet ist oder einem gegebenen eingebauten Typen entspricht.
as Versucht den Wert einem vorgegebenen Type zuzuweisen falls möglich.
self Bezieht sich auf die aktuelle Klassen Instanz.
tool Führt ein Skript im Editor aus.
signal Definiert ein Signal.
func Definiert eine Funktion.
static Definiert eine statische Funktion. Statische Member-Variablen sind nicht erlaubt.
const Definiert eine Konstante.
enum Definiert eine Aufzählung.
var Definiert eine Variable.
onready Initialisiert eine Variable sobald das Node, an dem das Skript angehängt wurde, und ihre Unterobjekte Teil des Szenenbaums sind.
export Speichert eine Variable zusammen mit der Ressource, an der sie hängt, und macht sie im Editor sicht- und modifizierbar.
setget Definiert setter und getter Funktionen für eine Variable.
breakpoint Helfer für den Editor für Haltepunkte des Debuggers.
preload Lädt eine Variable oder Klasse im Voraus, siehe Classes as resources.
yield Coprogramm Unterstützung, siehe Coroutines with yield.
assert Aktiviert eine Bedingung und protokolliert Fehler . Wird bei Nicht-Debug-Builds ignoriert. Siehe Assert keyword.
remote Anmerkungen zu RPC Netzwerke, siehe High-Level Mehrspieler Dokumentation.
master Anmerkungen zu RPC Netzwerke, siehe High-Level Mehrspieler Dokumentation.
puppet Anmerkungen zu RPC Netzwerke, siehe High-Level Mehrspieler Dokumentation.
remotesync Anmerkungen zu RPC Netzwerke, siehe High-Level Mehrspieler Dokumentation.
mastersync Anmerkungen zu RPC Netzwerke, siehe High-Level Mehrspieler Dokumentation.
puppetsync Anmerkungen zu RPC Netzwerke, siehe High-Level Mehrspieler Dokumentation.
PI Die π-Konstante.
TAU TAU-Konstante.
INF Konstante "Unendlichkeit". Wird für Vergleiche genutzt.
NAN Konstante "NAN" (not a number - Keine Zahl). Wird für Vergleiche genutzt.

Operatoren

Das folgende ist einer Liste der unterstützen Operatoren und ihrer Auswertungsreihenfolge.

Operator Beschreibung
x[index] Indexierung (höchste Priorität)
x.attribute Referenzierung eines Attributs
foo() Funktionsaufruf
is Prüfung des Instanztyps
~ Bitweise Negation
-x Negative / Unäre Negation
* / %

Multiplikation / Division / Modulus (Restbetrag)

Diese Operatoren verhalten sich wie in C++. Eine Ganzzahl-Division wird abgeschnitten anstelle eine gebrochener Zahl zu liefern und der % Operator ist nur verfügbar für Ganzzahlen ("fmod" für Fließkomma)

+ Addition / Verkettung von Arrays
- Subtraktion
<< >> Bit-Schieben
& Bitweises UND
^ Bitweises exklusiv-ODER (XOR)
| Bitweises (inklusiv-) ODER
< > == != >= <= Vergleiche
in Inhalt prüfen
! not Boolesches NICHT
and && Boolesches UND
or || Boolesches ODER
if x else Bedingte (ternäre) if/else Anweisung
as Typumwandlung
= += -= *= /= %= &= |= Zuweisung (niedrigste Priorität)

Literale

Literal Typ
45 Dezimale Ganzzahl (Basis 10)
0x8f51 Basis 16 (Hexadezimal) Ganzzahl
0b101010 Basis 2 (Binär) Ganzzahl
3.14, 58.1e-10 Fließkommazahl (reell)
"Hallo", "Hey" Zeichenketten
"""Hallo""" Mehrzeilige Zeichenkette
@"Node/Label" NodePath oder StringName
$NodeWeg Kurzform für get_node("NodePath")

Ganzzahlen und Gleitkommazahlen können durch _ getrennt werden um die Lesbarkeit zu verbessern. Die folgenden Möglichkeiten zum Schreiben von Zahlen sind alle gültig:

12_345_678  # Equal to 12345678.
3.141_592_7  # Equal to 3.1415927.
0x8080_0000_ffff  # Equal to 0x80800000ffff.
0b11_00_11_00  # Equal to 0b11001100.

Kommentare

Alles ab einem # bis zum Ende der Zeile wird ignoriert und als Kommentar aufgefasst.

# This is a comment.

Eingebaute Typen

Eingebaute Typen werden stapelweise zugewiesen. Sie werden als Werte übergeben. Dies bedeutet, dass bei jeder Zuweisung oder bei der Übergabe als Argumente an Funktionen eine Kopie erstellt wird. Die einzigen Ausnahmen sind Arrays und Dictionaries, die als Referenz übergeben werden, damit sie gemeinsam genutzt werden. (zusammengesetzte Arrays wie "PoolByteArray" werden weiterhin als Werte übergeben.)

Einfache eingebaute Typen

Eine Variable in GDScript kann mehreren eingebauten Typen zugewiesen werden.

null

null ist ein leerer Datentyp, der keine Information enthält und dem kein anderer Wert zugewiesen werden kann.

bool

Kurzform für Boolean-Datentyp, der nur true oder false enthalten kann.

int

Kurz für "Integer" (Ganzzahl): es kann eine Ganzzahl (positiv oder negativ) als 64-Bit Wert gespeichert werden, gleichbedeutend mit "int64_t" in C++.

float

Speichert eine reelle Zahl (Fließkommazahl) als 64-Bit Wert (doppelte Genauigkeit), gleichbedeutend mit "double" in C++. Anmerkung: Datenstrukturen wie Vector2, Vector3 und PoolRealArray speichern 32-Bit Fließkommazahlen (einfache Genauigkeit).

String

Eine Folge von Zeichen im Unicode-Format. Zeichenketten können die folgenden Escape-Sequenzen enthalten:

Escape Sequenz wird zu
\n Zeilenumbruch (Line Feed)
\t Horizontaler Tabulator
\r Wagenrücklauf (Carriage Return)
\a Alarm (Piepton/Klingel)
\b Backspace (Rückschritt)
\f neue Seite (Page Break)
\v Vertikaler Tabulator
\" doppelte Anführungszeichen
\' einfaches Anführungszeichen
\\ Backslash (Rückstrich oder umgekehrter Schrägstrich)
\uXXXX Unicode Codepoint XXXX (Hexadezimal, Case-Insensitive = Groß/Kleinschreibung ist egal)

GDScript unterstützt auch GDScript Zeichenketten formatieren.

eingebaute Vektor-Typen

Vector2

2D Vektor-Typ bestehend aus x und y. Zugriff kann auch als Feld erfolgen.

Rect2

2D Rechteckstypen mit zwei Vektor Feldern: position und size. Besitzt alternativ ein end Feld, welches position+size entspricht.

Vector3

3D Vektor Typ besitzt x, y und z Felder. Diese können auch als Array aufgerufen werden.

Transform2D

Eine 3x2 Matrix, welche für 2D Transformationen verwendet wird.

Plane

3D Ebenentyp in normalisierter Form, welcher ein normal Vektorfeld und eine skalare Distanz d besitzt.

Quat

Quaternion ist ein Datentyp, welcher für die Repräsentation von 3D-Rotationen verwendet wird. Er ist sehr nützlich für das Interpolieren von Rotationen.

AABB

Entlang der Achse ausgerichtete Begrenzungs-Box (oder 3D Box) besitzt 2 Vektorfelder: position und size. Besitzt alternativ ein end-Feld, welches position+size entspricht.

Basis

3x3 Matrix, welche für 3D Rotationen und Sklarierung verwendet wird. Es besitzt drei Vektorfelder (x, y und z) und kann auch als Array von 3D Vektoren aufgerufen werden.

Transform

3D Transform besitzen ein Basis Feld basis und ein Vector3 Feld origin.

In die Engine eingebaute Typen

Color

Der Color Datentyp besitzt jeweils ein r-, g-, b- und a-Feld. Der Zugriff kann auch über h, s und v erfolgen, was für hue (Farbwert)/saturation (Sättigung)/value (Dunkelstufe) steht.

NodePath

Hauptsächlich im Szenen-System genutzter kompilierter Pfad zu einem Node. Zuweisung kann einfach zu und von einer Zeichenkette erfolgen.

RID

Ressourcen ID (RID). Server nutzen generische RIDs, um unklare Daten zu referenzieren.

Object

Basisklasse für alles, was kein eingebauter Typ ist.

Container eingebaute Typen

Array

Generische Abfolge beliebiger Objekttypen, einschließlich anderer Arrays oder Wörterbücher (siehe unten). Die Größe des Arrays kann dynamisch geändert werden. Arrays werden ausgehend vom Index 0 indiziert. Negative Indizes zählen vom Ende an.

var arr = []
arr = [1, 2, 3]
var b = arr[1] # This is 2.
var c = arr[arr.size() - 1] # This is 3.
var d = arr[-1] # Same as the previous line, but shorter.
arr[0] = "Hi!" # Replacing value 1 with "Hi!".
arr.append(4) # Array is now ["Hi!", 2, 3, 4].

GDScript-Arrays werden aus Geschwindigkeitsgründen linear im Speicher zugewiesen. Große Arrays (mehr als Zehntausende von Elementen) können jedoch eine Speicherfragmentierung verursachen. Wenn dies ein Problem darstellt, stehen spezielle Arten von Arrays zur Verfügung. Diese akzeptieren nur einen einzigen Datentyp. Sie vermeiden Speicherfragmentierung und verbrauchen weniger Speicher, sind jedoch atomar und laufen tendenziell langsamer als generische Arrays. Sie werden daher nur für große Datenmengen empfohlen:

Dictionary

Zugehöriger Container, der durch eindeutige Schlüssel referenzierte Werte enthält.

var d = {4: 5, "A key": "A value", 28: [1, 2, 3]}
d["Hi!"] = 0
d = {
    22: "value",
    "some_key": 2,
    "other_key": [2, 3, 4],
    "more_key": "Hello"
}

Eine Tabellensyntax im Lua-Stil wird ebenfalls unterstützt. Der Lua-Stil verwendet = anstelle von : und benutzt keine Anführungszeichen, um Zeichenketten-Schlüssel zu markieren (was etwas weniger Schreibarbeit macht). Schlüssel, die in dieser Form geschrieben werden, können jedoch nicht mit einer Ziffer beginnen (wie jeder GDScript-Bezeichner).

var d = {
    test22 = "value",
    some_key = 2,
    other_key = [2, 3, 4],
    more_key = "Hello"
}

Um einen Schlüssel zu einem bestehenden Wörterbuch hinzuzufügen, greifen Sie wie ein vorhandener Schlüssel darauf zu und weisen Sie ihm einen zu:

var d = {} # Create an empty Dictionary.
d.waiting = 14 # Add String "waiting" as a key and assign the value 14 to it.
d[4] = "hello" # Add integer 4 as a key and assign the String "hello" as its value.
d["Godot"] = 3.01 # Add String "Godot" as a key and assign the value 3.01 to it.

var test = 4
# Prints "hello" by indexing the dictionary with a dynamic key.
# This is not the same as `d.test`. The bracket syntax equivalent to
# `d.test` is `d["test"]`.
print(d[test])

Bemerkung

Die Klammer-Syntax kann verwendet werden, um auf die Eigenschaften von jedem Object zuzugreifen, nicht nur aus Wörterbüchern. Beachten Sie, dass beim Indizieren einer nicht vorhandenen Eigenschaft ein Skriptfehler auftritt. Um dies zu vermeiden, verwenden Sie stattdessen die Methoden Object.get() und Object.set().

Daten

Variablen

Variablen können als Klassen-Member oder lokal in Funktionen existieren. Sie werden mit dem Schlüsselwort var erzeugt und können optional mit einem Wert initialisiert werden.

var a # Data type is 'null' by default.
var b = 5
var c = 3.8
var d = b + c # Variables are always initialized in order.

Variablen können optional eine Typspezifikation haben. Wenn ein Typ angegeben wird, muss die Variable immer denselben Typ haben, und der Versuch, einen inkompatiblen Wert zuzuweisen, führt zu einem Fehler.

Typen werden in der Variablendeklaration mit einem : (Doppelpunkt) nach dem Variablennamen gefolgt vom Typ angegeben.

var my_vector2: Vector2
var my_node: Node = Sprite.new()

Wenn die Variable innerhalb der Deklaration initialisiert wird, kann der Typ abgeleitet werden, sodass der Typname weggelassen werden kann:

var my_vector2 := Vector2() # 'my_vector2' is of type 'Vector2'.
var my_node := Sprite.new() # 'my_node' is of type 'Sprite'.

Ein Rückschluss auf den Typ ist nur möglich, wenn der zugewiesene Wert einen definierten Typ hat, andernfalls wird ein Fehler ausgelöst.

gültige Typen sind:

  • eingebaute Typen (Array, Vector2, int, String, etc.).
  • Engine-Klassen (Node, Ressource, Referenz, usw.).
  • Konstante Namen, wenn sie eine Skript-Ressource enthalten (MyScript, wenn man const MyScript = preload("res://my_script.gd") deklariert hat).
  • Andere Klassen im gleichen Skript, unter Berücksichtigung des Geltungsbereichs (InnerClass.NestedClass, wenn man class NestedClass innerhalb der class InnerClass im gleichen Geltungsbereich deklariert hat).
  • Skriptklassen, die mit dem Schlüsselwort class_name deklariert wurden.

Casting (Typumwandlung)

Werte, die typisierten Variablen zugewiesen werden, müssen einen kompatiblen Typ haben. Wenn es erforderlich ist, einen Wert von einem bestimmten Typ zu erzwingen, insbesondere für Objekttypen, können Sie den Casting-Operator as verwenden.

Das Umwandeln zwischen Objekttypen führt zu demselben Objekt, wenn der Wert vom selben Typ oder einem Untertyp des Umwandlungstyps ist.

var my_node2D: Node2D
my_node2D = $Sprite as Node2D # Works since Sprite is a subtype of Node2D.

Wenn der Wert kein Subtyp ist, führt die Casting-Operation zu einem null -Wert.

var my_node2D: Node2D
my_node2D = $Button as Node2D # Results in 'null' since a Button is not a subtype of Node2D.

Bei eingebauten Typen werden sie nach Möglichkeit zwangsweise konvertiert, da sonst die Engine einen Fehler auslöst.

var my_int: int
my_int = "123" as int # The string can be converted to int.
my_int = Vector2() as int # A Vector2 can't be converted to int, this will cause an error.

Casting ist auch nützlich, um bei der Interaktion mit dem Szenenbaum bessere typsichere Variablen zu haben:

# Will infer the variable to be of type Sprite.
var my_sprite := $Character as Sprite

# Will fail if $AnimPlayer is not an AnimationPlayer, even if it has the method 'play()'.
($AnimPlayer as AnimationPlayer).play("walk")

Konstanten

Constants are values you cannot change when the game is running. Their value must be known at compile-time. Using the const keyword allows you to give a constant value a name. Trying to assign a value to a constant after it's declared will give you an error.

We recommend using constants whenever a value is not meant to change.

const A = 5
const B = Vector2(20, 20)
const C = 10 + 20 # Constant expression.
const D = Vector2(20, 30).x # Constant expression: 20.
const E = [1, 2, 3, 4][0] # Constant expression: 1.
const F = sin(20) # 'sin()' can be used in constant expressions.
const G = x + 20 # Invalid; this is not a constant expression!
const H = A + 20 # Constant expression: 25 (`A` is a constant).

Obwohl der Typ der Konstanten aus dem zugewiesenen Wert abgeleitet wird, ist es auch möglich, eine explizite Typspezifikation hinzuzufügen:

const A: int = 5
const B: Vector2 = Vector2()

Das Zuweisen eines Werts eines inkompatiblen Typs führt zu einem Fehler.

Bemerkung

Da Arrays und Wörterbücher als Referenz übergeben werden, sind Konstanten "flach". Das heißt, wenn Sie ein konstantes Array oder Wörterbuch deklarieren, kann es danach noch geändert werden. Sie können jedoch keinem anderen Wert zugewiesen werden.

Enumeratoren (Aufzählungen)

Enumeratoren sind im Grunde ein Kürzel für Konstanten und sind nützlich, wenn aufeinanderfolgende Ganzzahlen Kontanten zugeordnet werden sollen.

Wenn Sie der Aufzählung einen Namen übergeben, werden alle Schlüssel in ein konstantes Wörterbuch dieses Namens aufgenommen.

Wichtig

In Godot 3.1 und höher werden Schlüssel in einer benannten Aufzählung nicht als globale Konstanten registriert. Auf sie sollte vor dem Namen der Aufzählung (Name.KEY) zugegriffen werden. siehe ein Beispiel unten.

enum {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT}
# Is the same as:
const TILE_BRICK = 0
const TILE_FLOOR = 1
const TILE_SPIKE = 2
const TILE_TELEPORT = 3

enum State {STATE_IDLE, STATE_JUMP = 5, STATE_SHOOT}
# Is the same as:
const State = {STATE_IDLE = 0, STATE_JUMP = 5, STATE_SHOOT = 6}
# Access values with State.STATE_IDLE, etc.

Funktionen

Funktionen gehören immer zu einer Klasse. Die Priorität für die variable Suche ist: local → class member → global. Die Variable self ist immer verfügbar und wird als Option für den Zugriff auf Klassenmitglieder bereitgestellt, wird aber nicht immer benötigt (und sollte im Gegensatz zu Python nicht als erstes Argument der Funktion gesendet werden).

func my_function(a, b):
    print(a)
    print(b)
    return a + b  # Return is optional; without it 'null' is returned.

Eine Funktion kann jederzeit zurückkehren. Der Standard-Rückgabewert ist null.

Funktionen können auch eine Typspezifikation für die Argumente und für den Rückgabewert haben. Typen für Argumente können auf ähnliche Weise wie Variablen hinzugefügt werden:

func my_function(a: int, b: String):
    pass

Wenn ein Funktionsargument einen Standardwert hat, kann auf den Typ geschlossen werden:

func my_function(int_arg := 42, String_arg := "string"):
    pass

Der Rückgabetyp der Funktion kann nach der Argumentliste mit dem Pfeiltoken (`` -> ``) angegeben werden:

func my_int_function() -> int:
    return 0

Funktionen mit einem Rückgabetyp müssen einen richtigen Wert zurückgeben. Wenn Sie den Typ auf void setzen, gibt die Funktion nichts zurück. Void-Funktionen können mit dem Schlüsselwort return frühzeitig beendet werden, sie können jedoch keinen Wert zurückgeben.

void_function() -> void:
    return # Can't return a value

Bemerkung

Nicht-void-Funktionen müssen immer einen Wert zurückgeben. Wenn Ihr Code also Verzweigungsanweisungen enthält (z.B. ein if/else-Konstrukt), müssen alle möglichen Pfade eine Rückgabe haben. Wenn Sie beispielsweise ein return in einem if-Block haben, aber nicht danach, gibt der Editor einen Fehler aus, da die Funktion keinen gültigen Wert für die Rückgabe hat, wenn der Block nicht ausgeführt wird.

Funktionen referenzieren

Im Gegensatz zu Python sind Funktionen keine erste Klasse Objekte in GDScript. Das bedeutet, sie können nicht in Variablen gespeichert werden, als Argument für eine andere Funktion übergeben werden oder von anderen Funktionen zurückgegeben werden – aus Gründen der Geschwindigkeit.

Um eine Funktion zur Laufzeit namentlich zu referenzieren (z.B. um sie in einer Variablen zu speichern oder als Argument an eine andere Funktion zu übergeben), müssen die Helfer call oder funcref verwendet werden:

# Call a function by name in one step.
my_node.call("my_function", args)

# Store a function reference.
var my_func = funcref(my_node, "my_function")
# Call stored function reference.
my_func.call_func(args)

Statische Funktionen

Eine Funktion kann als statisch deklariert werden. Wenn eine Funktion statisch ist, hat sie keinen Zugriff auf die Member der Instanz oder self. Dies ist vor allem nützlich um Bibliotheken mit Hilfsfunktionen zu erzeugen:

static func sum2(a, b):
    return a + b

Anweisungen und Kontrollstrukturen

Ausdrücke sind Standard und können Zuweisungen sein, Funktionsaufrufe, Flußkontrollstrukturen, usw. (siehe unten). ``;``als Trennzeichen zwischen Ausdrücken ist optional.

if/else/elif

Einfache Verzweigungen werden mit dem if/else/elif Syntax erstellt. Klammern um die Bedingungen zu setzten ist möglich, aber nicht zwingend notwendig. Angesichts der Tabulator basierten Einrückung kann elif anstelle von else/if verwendet werden, um auf dem selben Level der Einrückung zu bleiben.

if [expression]:
    statement(s)
elif [expression]:
    statement(s)
else:
    statement(s)

Kurze Befehle können auf die selbe Zeile wie die Bedingung geschrieben werden:

if 1 + 1 == 2: return 2 + 2
else:
    var x = 3 + 3
    return x

Manchmal möchte man vielleicht anfangs einen anderen Wert zuweisen, basierend auf einem booleschen Ausdruck. Hierfür ist der ternäre IF-Ausdruck nützlich:

var x = [value] if [expression] else [value]
y += 3 if y < 10 else -1

while

Einfache Schleifen werden mit dem while Syntax erstellt. Schleifen kann man mit break abbrechen, oder mit continue in den nächsten Durchlauf springen lassen:

while [expression]:
    statement(s)

for

Um einen Bereich wie ein Array oder eine Tabelle zu durchlaufen, wird eine for -Schleife verwendet. Beim Iterieren über ein Array wird das aktuelle Array-Element in der Schleifenvariablen gespeichert. Beim Durchlaufen eines Wörterbuchs wird der Schlüssel in der Schleifenvariablen gespeichert.

for x in [5, 7, 11]:
    statement # Loop iterates 3 times with 'x' as 5, then 7 and finally 11.

var dict = {"a": 0, "b": 1, "c": 2}
for i in dict:
    print(dict[i]) # Prints 0, then 1, then 2.

for i in range(3):
    statement # Similar to [0, 1, 2] but does not allocate an array.

for i in range(1, 3):
    statement # Similar to [1, 2] but does not allocate an array.

for i in range(2, 8, 2):
    statement # Similar to [2, 4, 6] but does not allocate an array.

for c in "Hello":
    print(c) # Iterate through all characters in a String, print every letter on new line.

for i in 3:
    statement # Similar to range(3)

for i in 2.2:
    statement # Similar to range(ceil(2.2))

match

Eine match-Anweisung benutzt man, um die Ausführung des Programms zu verzweigen. Sie ist äquivalent zur switch-Anweisung, wie sie aus vielen anderen Sprachen bekannt ist, aber bietet darüberhinaus zusätzliche Funktionalität.

Grundlegende Syntax:

match [expression]:
    [pattern](s):
        [block]
    [pattern](s):
        [block]
    [pattern](s):
        [block]

Crashkurs für jene, die mit switch-Anweisungen vertraut sind:

  1. Ersetze switch mit match.
  2. Entferne case.
  3. Entfernt jedes break. Sollte das standardmäßige break ungewünscht sein, so kann durch ein continue ein Fortfahren erzielt werden.
  4. Ändere default zu einem einzelnen Unterstrich.

Kontrollfluss:

Die Muster werden von oben nach unten abgeglichen. Wenn ein Muster passt, wird der entsprechende Block ausgeführt. Danach setzt die Ausführung unter der match-Anweisung fort. Wenn stattdessen ein Durchrutschen (Fallthrough) gewünscht ist, kann ein continue benutzt werden, um die Ausführung im aktuellen Block anzuhalten und in die Folgenden zu springen.

Es gibt 6 Arten von Mustern:

  • Konstanten-Muster

    Konstanten einfachen Typs, wie Zahlen und Zeichenketten:

    match x:
        1:
            print("We are number one!")
        2:
            print("Two are better than one!")
        "test":
            print("Oh snap! It's a string!")
    
  • Variablen-Muster

    Vergleicht mit dem Inhalt einer Variable oder Aufzählung:

    match typeof(x):
        TYPE_REAL:
            print("float")
        TYPE_STRING:
            print("text")
        TYPE_ARRAY:
            print("array")
    
  • Platzhalter-Muster

    Dieses Schema passt auf alles. Es wird als einzelner Unterstrich geschrieben.

    Es kann als das Äquivalent genutzt werden von default in einer switch-Anweisung in anderen Sprachen.:

    match x:
        1:
            print("It's one!")
        2:
            print("It's one times two!")
        _:
            print("It's not 1 or 2. I don't care to be honest.")
    
  • Verbindungs-Muster

    Ein Verbindungs-Muster erzeugt eine neue Variable. Wie das Platzhalter-Muster passt es auf alles und gibt diesem Wert einen Namen. Es ist besondern hilfreich beim Feld- und Wörterbuch-Muster:

    match x:
        1:
            print("It's one!")
        2:
            print("It's one times two!")
        var new_var:
            print("It's not 1 or 2, it's ", new_var)
    
  • Array-Muster

    Entspricht einem Array. Jedes einzelne Element des Array-Musters ist selbst ein Muster, sodass Sie es verschachteln können.

    Die Länge des Arrays wird zuerst getestet. Sie muss dieselbe Größe wie das Muster haben, andernfalls stimmt das Muster nicht überein.

    Array mit offenem Ende: Ein Array kann größer als das Muster sein, indem das letzte Untermuster mit .. erstellt wird.

    Jedes Untermuster muss durch Kommas getrennt werden.

    match x:
        []:
            print("Empty array")
        [1, 3, "test", null]:
            print("Very specific array")
        [var start, _, "test"]:
            print("First element is ", start, ", and the last is \"test\"")
        [42, ..]:
            print("Open ended array")
    
  • Wörterbuch-Muster

    Funktioniert auf die gleiche Weise wie das Feld-Muster, jeder Schlüssel muss ein gleichbleibendes Muster haben.

    Die Größe des Wörterbuchs wird zuerst getestet. Es muss dieselbe Größe wie das Muster haben, andernfalls stimmt das Muster nicht überein.

    Wörterbuch mit offenem Ende: Ein Wörterbuch kann größer als das Muster sein, indem das letzte Untermuster mit .. erstellt wird.

    Jede Untermuster muss durch ein Komma getrennt werden.

    Falls kein Wert angegeben wird, wird nur die Existenz des Schlüssels überprüft.

    Ein Wertemuster wird durch ein : vom Schlüsselmuster getrennt.

    match x:
        {}:
            print("Empty dict")
        {"name": "Dennis"}:
            print("The name is Dennis")
        {"name": "Dennis", "age": var age}:
            print("Dennis is ", age, " years old.")
        {"name", "age"}:
            print("Has a name and an age, but it's not Dennis :(")
        {"key": "godotisawesome", ..}:
            print("I only checked for one entry and ignored the rest")
    
  • Vielfach-Muster

    Sie können auch mehrere durch Komma getrennte Muster angeben. Diese Muster dürfen keine Bindungen enthalten.

    match x:
        1, 2, 3:
            print("It's 1 - 3")
        "Sword", "Splash potion", "Fist":
            print("Yep, you've taken damage")
    

Klassen

Standardmäßig sind alle Skriptdateien namenlose Klassen. In diesem Fall können Sie sie nur über den Dateipfad referenzieren, entweder über einen relativen oder einen absoluten Pfad. Wenn Sie beispielsweise eine Skriptdatei character.gd benennen:

# Inherit from 'Character.gd'.

extends "res://path/to/character.gd"

# Load character.gd and create a new node instance from it.

var Character = load("res://path/to/character.gd")
var character_node = Character.new()

Sie können ein Skript benennen und als Typ im Editor mit dem Schlüsselwort class_name, gefolgt von dem Namen der Klasse, registrieren. Gefolgt von einem Komma können Sie optional einen Pfad zu einer Bilddatei hinzufügen. Sie finden Ihren neuen Typen dann im Dialogfeld "Nodes- oder Ressourcenerstellung".

# Item.gd

extends Node
class_name Item, "res://interface/icons/item.png"
../../../_images/class_name_editor_register_example.png

Hier ist ein Beispiel für eine Klassendatei:

# Saved as a file named 'character.gd'.

class_name Character


var health = 5


func print_health():
    print(health)


func print_this_script_three_times():
    print(get_script())
    print(ResourceLoader.load("res://character.gd"))
    print(Character)

Bemerkung

Die Klassensyntax von Godot ist kompakt: Sie kann nur Mitgliedsvariablen oder Funktionen enthalten. Sie können statische Funktionen verwenden, jedoch keine statischen Mitgliedsvariablen. Auf die gleiche Weise initialisiert die Engine jedes Mal Variablen wenn Sie eine Instanz erstellen, einschließlich Arrays und Wörterbücher. Dies dient der Thread-Sicherheit, da Skripte in separaten Threads initialisiert werden können, ohne dass der Benutzer dies weiß.

Vererbung

Eine Klasse (gespeichert als Datei) kann erben von:

  • Einer globalen Klasse.
  • Einer anderen Klassendatei.
  • Eine lokale Klasse innerhalb einer anderen Klassendatei.

Mehrfache Vererbung ist nicht erlaubt.

Vererbung benutzt das Schlüsselwort extends:

# Inherit/extend a globally available class.
extends SomeClass

# Inherit/extend a named class file.
extends "somefile.gd"

# Inherit/extend an inner class in another file.
extends "somefile.gd".SomeInnerClass

Um zu prüfen, ob eine gegebene Instanz von einer gegebenen Klasse erbt, verwendet man das Schlüsselwort is:

# Cache the enemy class.
const Enemy = preload("enemy.gd")

# [...]

# Use 'is' to check inheritance.
if entity is Enemy:
    entity.apply_damage()

Um eine Funktion in einer übergeordneten Klasse aufzurufen (d.h. eine extend-ed in Ihrer aktuellen Klasse), stellen Sie dem Funktionsnamen ein . vor:

.base_func(args)

Dies ist besonders nützlich, da Funktionen in erweiterten Klassen andere Funktionen mit demselben Namen in ihren übergeordneten Klassen ersetzen. Wenn Sie sie weiterhin aufrufen möchten, können Sie ihnen einen . voranstellen (wie das Schlüsselwort super in anderen Sprachen):

func some_func(x):
    .some_func(x) # Calls the same function on the parent class.

Bemerkung

Standardfunktionen wie _init, und die meisten Benachrichtigungen wie _enter_tree, _exit_tree, _process, _physics_process, etc. werden in allen Elternklassen automatisch aufgerufen. Es besteht keine Notwendigkeit, sie beim Überladen explizit aufzurufen.

Klassen-Konstruktor

Der Klassenkonstruktor, der bei der Klasseninstantiierung aufgerufen wird, heißt _init. Wie bereits erwähnt, werden die Konstruktoren von Elternklassen bei der Vererbung einer Klasse automatisch aufgerufen. Es besteht also normalerweise keine Notwendigkeit, ._init() explizit aufzurufen.

Anders als beim Aufruf einer regulären Funktion, wie im obigen Beispiel mit .some_func, werden Argumente, wenn der Konstruktor aus der geerbten Klasse Argumente entgegennimmt, wie folgt übergeben:

func _init(args).(parent_args):
   pass

Dies wird besser anhand von Beispielen erklärt. Betrachten Sie dieses Szenario:

# State.gd (inherited class)
var entity = null
var message = null


func _init(e=null):
    entity = e


func enter(m):
    message = m


# Idle.gd (inheriting class)
extends "State.gd"


func _init(e=null, m=null).(e):
    # Do something with 'e'.
    message = m

Hier müssen ein paar Sachen berücksichtigt werden:

  1. Wenn die geerbte Klasse (State.gd) einen _init-Konstruktor definiert, der Argumente übernimmt (e in diesem Fall), dann muss die vererbende Klasse (Idle.gd) ebenfalls _init definieren und passende Parameter an _init von State.gd übergeben.

  2. Idle.gd kann eine andere Anzahl an Argumenten besitzen als die Basisklasse State.gd.

  3. Im obigen Beispiel ist das e im Konstruktor von State.gd``das gleiche wie das ``e in Idle.gd.

  4. Wenn der Idle.gd's _init Konstruktor 0 Argumente annimmt, muss er immer noch irgendeinen Wert an die `State.gd Elternklasse übergeben, selbst wenn sie nichts tut. Das bringt uns zu der Tatsache, dass man auch im Basiskonstruktor Literale übergeben kann, nicht nur Variablen. z.B.:

    # Idle.gd
    
    func _init().(5):
        pass
    

Innere Klassen

Eine Klassendatei kann lokale Klassen beinhalten. Lokale Klassen werden durch das class Schlüsselwort definiert. Sie werden mithilfe der Klassenname.new()-Funktion instanziert.

# Inside a class file.

# An inner class in this class file.
class SomeInnerClass:
    var a = 5


    func print_value_of_a():
        print(a)


# This is the constructor of the class file's main class.
func _init():
    var c = SomeInnerClass.new()
    c.print_value_of_a()

Klassen als Ressourcen

Klassen, die als Datei gespeichert sind, werden als resources behandelt. Sie müssen von der Festplatte geladen werden, um auf sie in anderen Klassen zuzugreifen. Dies macht man mit den Funktionen load oder preload (siehe weiter unten). Das Instanzieren einer geladenen Klassenressource erledigt man durch Aufruf der new-Funktion auf dem Klassenobjekt:

# Load the class resource when calling load().
var my_class = load("myclass.gd")

# Preload the class only once at compile time.
const MyClass = preload("myclass.gd")


func _init():
    var a = MyClass.new()
    a.some_function()

Exporte

Bemerkung

Die Dokumentation über Exportieren wurde nach GDScript Exporte verschoben.

Setter/Getter

Es ist oft hilfreich zu wissen, ob sich eine Variable einer Klasse verändert, aus welchen Gründen auch immer. Es ist vielleicht auch wünschenswert sie auf eine gewisse Art vor Zugriffen zu schützen.

Dafür bietet GDScript einen setter/getter Syntax mit dem setget Schlüsselwort. Es wird direkt nach der Definition einer Variable genutzt:

var variable = value setget setterfunc, getterfunc

Wann immer der Wert von variable durch eine externe Quelle modifiziert wird (d.h. nicht aus dem lokalen Gebrauch in der Klasse), wird die setter Funktion (oben setterfunc) aufgerufen. Dies geschieht bevor der Wert geändert wird. Der setter muß entscheiden, was mit dem neuen Wert geschehen soll. Umgekehrt, wenn auf variable zugegriffen wird, muß die getter-Funktion (getterfunc oben) den gewünschten Wert zurückgeben. Unten ist ein Beispiel:

var my_var setget my_var_set, my_var_get


func my_var_set(new_value):
    my_var = new_value


func my_var_get():
    return my_var # Getter must return a value.

Eine der Funktionen setter oder getter kann weggelassen werden

# Only a setter.
var my_var = 5 setget my_var_set
# Only a getter (note the comma).
var my_var = 5 setget ,my_var_get

Setter und Getter sind nützlich, wenn Variablen in Skripten oder Plugins zum Editor exportiert werden, um Eingaben zu validieren.

Wie gesagt, lokaler Zugriff wird nicht den Setter und Getter auslösen. Hier ist eine Veranschaulichung dafür:

func _init():
    # Does not trigger setter/getter.
    my_integer = 5
    print(my_integer)

    # Does trigger setter/getter.
    self.my_integer = 5
    print(self.my_integer)

Werkzeug-Modus

Standardmäßig werden Skripte nicht innerhalb des Editors ausgeführt und nur die exportierten Eigenschaften können geändert werden. In einigen Fällen ist es erwünscht, dass sie innerhalb des Editors ausgeführt werden (solange sie keinen Spielcode ausführen oder dies manuell vermeiden). Hierfür existiert das Schlüsselwort tool, das an den Anfang der Datei gesetzt werden muss:

tool
extends Button


func _ready():
    print("Hello")

Siehe Code im Editor ausführen für weitere Informationen.

Warnung

Seien Sie vorsichtig, wenn Sie Nodes mit queue_free() oder free() in einem tool Skript freigeben (insbesondere der Eigentümer des Skripts selbst). Da tool Skripte ihren Code im Editor ausführen, kann ihr Missbrauch zum Absturz des Editors führen.

Speicher-Management

Wenn eine Klasse von: ref: class_Reference erbt, werden Instanzen freigegeben, wenn sie nicht mehr verwendet werden. Es gibt keinen Müllsammler , nur Referenzzählung. Standardmäßig erweitern alle Klassen, die keine Vererbung definieren, ** Referenz **. Wenn dies nicht gewünscht ist, muss eine Klasse manuell Folgendes erben: ref: class_Object und` instance.free() `aufrufen. Um Referenzzyklen zu vermeiden, die nicht freigegeben werden können, wird eine Funktion "weakref" zum Erstellen schwacher Referenzen bereitgestellt.

Wenn keine Referenzen verwendet werden, kann alternativ mit is_instance_valid(instance) überprüft werden, ob ein Objekt freigegeben wurde.

Signale

Signale sind ein Werkzeug zum Senden von Nachrichten von einem Objekt, auf die andere Objekte reagieren können. Verwenden Sie das Schlüsselwort signal, um benutzerdefinierte Signale für eine Klasse zu erstellen.

extends Node


# A signal named health_depleted.
signal health_depleted

Bemerkung

Signale sind eine Rückruffunktion <https://de.wikipedia.org/wiki/R%C3%BCckruffunktion> _ Mechanismus. Sie übernehmen auch die Rolle der Beobachter, ein gängiges Programmiermuster. Weitere Informationen finden Sie im Observer-Tutorial (in englischer Sprache)<https://gameprogrammingpatterns.com/observer.html> _ im eBook Spielprogrammiermuster.

Sie können diese Signale auf dieselbe Weise mit Methoden verbinden, wie Sie integrierte Signale von Nodes wie Button oder :ref:` class_RigidBody` verbinden.

Im folgenden Beispiel verbinden wir das Signal "health_depleted" von einem "Character" -Node mit einem "Game" -Node. Wenn der Character-Node das Signal aussendet, wird des Game nodes``_on_Character_health_depleted``genannt

# Game.gd

func _ready():
    var character_node = get_node('Character')
    character_node.connect("health_depleted", self, "_on_Character_health_depleted")


func _on_Character_health_depleted():
    get_tree().reload_current_scene()

Sie können so viele Argumente wie Sie möchten zusammen mit einem Signal ausgeben.

Hier ist ein Beispiel, wo dies nützlich ist. Angenommen, wir möchten, dass eine Lebensleiste auf dem Bildschirm mit einer Animation auf Gesundheitsänderungen reagiert, aber wir möchten in unserem Szenenbaum die Benutzeroberfläche vom Spieler getrennt halten.

In unserem Character.gd -Skript definieren wir ein health_changed Signal und senden es mit: ref: Object.emit_signal() <class_Object_method_emit_signal> und von einem Game Node weiter oben im Szenenbaum, wir verbinden ihn mit der Lebensleiste mit der: ref: Object.connect() <class_Object_method_connect> Methode:

# Character.gd

...
signal health_changed


func take_damage(amount):
    var old_health = health
    health -= amount

    # We emit the health_changed signal every time the
    # character takes damage.
    emit_signal("health_changed", old_health, health)
...
# Lifebar.gd

# Here, we define a function to use as a callback when the
# character's health_changed signal is emitted.

...
func _on_Character_health_changed(old_value, new_value):
    if old_value > new_value:
        progress_bar.modulate = Color.red
    else:
        progress_bar.modulate = Color.green

    # Imagine that `animate` is a user-defined function that animates the
    # bar filling up or emptying itself.
    progress_bar.animate(old_value, new_value)
...

Bemerkung

Um Signale zu verwenden, muss Ihre Klasse die Objekt-Klasse oder einen beliebigen Typ erweitern, wie zum Beispiel Node, KinematicBody, Control ...

Im `` Game`` -Node erhalten wir sowohl den `` Charakter`` als auch den `` Lebensleiste`` Node und verbinden dann den Charakter, der das Signal aussendet, mit dem Empfänger, in diesem Fall dem `` Lebensleiste`` Knoten .

# Game.gd

func _ready():
    var character_node = get_node('Character')
    var lifebar_node = get_node('UserInterface/Lifebar')

    character_node.connect("health_changed", lifebar_node, "_on_Character_health_changed")

Dies ermöglicht es der Lifebar, auf Gesundheitsänderungen zu reagieren, ohne sie mit dem Character-Knoten zu koppeln.

Sie können optionale Argumentnamen in Klammern nach der Definition des Signals schreiben:

# Defining a signal that forwards two arguments.
signal health_changed(old_value, new_value)

Diese Argumente werden im Node-Dock des Editors angezeigt und Godot kann sie verwenden um Rückruffunktionen für Sie zu generieren. Sie können jedoch immer noch eine beliebige Anzahl von Argumenten angeben, wenn Sie Signale ausgeben. Es liegt an Ihnen die richtigen Werte auszugeben.

../../../_images/gdscript_basics_signals_node_tab_1.png

GDScript kann ein Array von Werten an Verbindungen zwischen einem Signal und einer Methode binden. Wenn das Signal ausgegeben wird, empfängt die Rückrufmethode die gebundenen Werte. Diese gebundenen Argumente sind für jede Verbindung einzigartig aber die Werte bleiben gleich.

Mit diesem Wertearray können Sie der Verbindung zusätzliche konstante Informationen hinzufügen, wenn das ausgegebene Signal selbst Ihnen keinen Zugriff auf alle benötigten Daten bietet.

Aufbauend auf dem obigen Beispiel möchten wir ein Protokoll des von jedem Charakter erlittenen Schadens auf dem Bildschirm anzeigen, z. B. "Spieler1 hat 22 Schaden erlitten". Das `` health_changed`` Signal gibt uns nicht den Namen des Charakters, der Schaden genommen hat. Wenn wir also das Signal mit der In-Game-Konsole verbinden, können wir den Namen des Charakters in das Argument binds array einfügen:

# Game.gd

func _ready():
    var character_node = get_node('Character')
    var battle_log_node = get_node('UserInterface/BattleLog')

    character_node.connect("health_changed", battle_log_node, "_on_Character_health_changed", [character_node.name])

Unser `` BattleLog`` -Node empfängt jedes Element im Binds-Array als zusätzliches Argument

# BattleLog.gd

func _on_Character_health_changed(old_value, new_value, character_name):
    if not new_value <= old_value:
        return

    var damage = old_value - new_value
    label.text += character_name + " took " + str(damage) + " damage."

Co-Routinen mit yield

GDScript bietet Unterstützung für die integrierte Funktion Coroutinen<https://en.wikipedia.org/wiki/Coroutine> _ über die integrierte Funktion: ref: yield <class_ @ GDScript_method_yield>. Das Aufrufen von `` Yield() `` kehrt sofort von der aktuellen Funktion zurück, wobei der aktuelle eingefrorene Zustand dieselbe Funktion wie der Rückgabewert hat. Wenn Sie für dieses resultierende Objekt `` resume() `` aufrufen, wird die Ausführung fortgesetzt und alles zurückgegeben, was die Funktion zurückgibt. Nach der Wiederaufnahme wird das Statusobjekt ungültig. Hier ist ein Beispiel:

func my_func():
    print("Hello")
    yield()
    print("world")


func _ready():
    var y = my_func()
    # Function state saved in 'y'.
    print("my dear")
    y.resume()
    # 'y' resumed and is now an invalid state.

Ausgabe:

Hello
my dear
world

Es ist auch möglich Werte zwischen yield() und resume() zu übergeben, zum Beispiel:

func my_func():
    print("Hello")
    print(yield())
    return "cheers!"


func _ready():
    var y = my_func()
    # Function state saved in 'y'.
    print(y.resume("world"))
    # 'y' resumed and is now an invalid state.

Ausgabe:

Hello
world
cheers!

Denken Sie daran, den neuen Funktionsstatus zu speichern, wenn Sie mehrere yields verwenden:

func co_func():
    for i in range(1, 5):
        print("Turn %d" % i)
        yield();


func _ready():
    var co = co_func();
    while co is GDScriptFunctionState && co.is_valid():
        co = co.resume();

Co-Routinen & Signale

Die wahre Stärke der Verwendung von "Yield" liegt in der Kombination mit Signalen. `` Yield`` kann zwei Argumente akzeptieren, ein Objekt und ein Signal. Wenn das Signal empfangen wird, beginnt die Ausführung erneut. Hier sind einige Beispiele:

# Resume execution the next frame.
yield(get_tree(), "idle_frame")

# Resume execution when animation is done playing.
yield(get_node("AnimationPlayer"), "animation_finished")

# Wait 5 seconds, then resume execution.
yield(get_tree().create_timer(5.0), "timeout")

Koroutinen selbst verwenden das Signal completed, wenn sie in einen ungültigen Zustand übergehen, zum Beispiel:

func my_func():
    yield(button_func(), "completed")
    print("All buttons were pressed, hurray!")


func button_func():
    yield($Button0, "pressed")
    yield($Button1, "pressed")

my_func wird erst weiter ausgeführt, sobald beide Buttons gedrückt wurden.

Sie können das Argument des Signals auch abfragen, sobald es von einem Objekt ausgegeben wird:

# Wait for when any node is added to the scene tree.
var node = yield(get_tree(), "node_added")

Sollten Sie sich unsicher sein, ob eine Funktion nachgibt oder nicht, oder ob sie mehrfach nachgeben kann, können Sie bedingt bis zum completed Signal nachgeben:

func generate():
    var result = rand_range(-1.0, 1.0)

    if result < 0.0:
        yield(get_tree(), "idle_frame")

    return result


func make():
    var result = generate()

    if result is GDScriptFunctionState: # Still working.
        result = yield(result, "completed")

    return result

Dies stellt sicher, dass die Funktion alles zurückgibt, was sie zurückgeben sollte, unabhängig davon, ob Coroutinen intern verwendet wurden. Beachten Sie, dass die Verwendung von `` während`` hier redundant wäre, da das Signal `` abgeschlossen`` nur ausgegeben wird, wenn die Funktion nicht mehr nachgibt.

Onready Schlüsselwort

Bei der Verwendung von Nodes ist es üblich, Verweise auf Teile der Szene in einer Variablen zu behalten. Da Szenen nur beim Aufrufen des aktiven Szenenbaums konfiguriert werden müssen, können die Unterknoten nur abgerufen werden, wenn ein Aufruf von "Node._ready()" erfolgt.

var my_label


func _ready():
    my_label = get_node("MyLabel")

Dies kann etwas umständlich werden, insbesondere wenn sich Nodes und externe Referenzen häufen. Zu diesem Zweck hat GDScript das Schlüsselwort "onready", das die Initialisierung einer Mitgliedsvariablen verzögert, bis "_ready()" "aufgerufen wird. Es kann den obigen Code durch eine einzelne Zeile ersetzen

onready var my_label = get_node("MyLabel")

Assert Schlüsselwort

Das`` behaupten`` Schlüsselwort kann verwendet werden, um Bedingungen im Debug-Builds zu überprüfen. Diese Behauptungen werden in Nicht-Debug-Builds ignoriert. Dies bedeutet, dass der als Argument übergebene Ausdruck in einem Release-Modus exportierten Projekt nicht ausgewertet wird. Aus diesem Grund dürfen Behauptungen ** keine ** Ausdrücke enthalten, die Nebenwirkungen haben. Andernfalls hängt das Verhalten des Skripts davon ab, ob das Projekt in einem Debug-Build ausgeführt wird.

# Check that 'i' is 0. If 'i' is not 0, an assertion error will occur.
assert(i == 0)

Wenn Sie ein Projekt über den Editor ausführen, wird das Projekt angehalten, wenn ein Behauptung Fehler auftritt.