Using signals¶
In dieser Lektion werden wir uns mit Signalen beschäftigen. Das sind Nachrichten, die Nodes aussenden, wenn etwas Bestimmtes mit ihnen passiert, z. B. wenn eine Taste gedrückt wird. Andere Nodes können sich mit diesem Signal verbinden und eine Funktion aufrufen, wenn das Ereignis eintritt.
Es handelt sich um einen in Godot eingebauten Delegationsmechanismus, der es einem Spielobjekt ermöglicht, auf eine Änderung in einem anderen zu reagieren, ohne dass sie sich gegenseitig referenzieren. Die Verwendung von Signalen begrenzt die Kopplung und hält den Code flexibel.
Sie könnten zum Beispiel einen Lebensbalken auf dem Bildschirm haben, der die Gesundheit des Spielers anzeigt. Wenn der Spieler Schaden erleidet oder einen Heiltrank benutzt, soll der Balken die Veränderung anzeigen. Dazu würden Sie in Godot Signale verwenden.
Bemerkung
Wie in der Einleitung erwähnt, sind Signale Godot's Version des Beobachtermusters. Sie können hier mehr darüber erfahren: https://gameprogrammingpatterns.com/observer.html
We will now use a signal to make our Godot icon from the previous lesson (Eingaben des Spielers abhören) move and stop by pressing a button.
Eine Szene einrichten¶
To add a button to our game, we will create a new "main" scene which will
include both a button and the Sprite.tscn
scene that we scripted in previous
lessons.
Erstellen Sie eine neue Szene, indem Sie das Menü Szene -> Neue Szene aufrufen.

Klicken Sie im Szenendock auf die Schaltfläche 2D-Szene. Dadurch wird ein Node2D als Wurzel hinzugefügt.

Klicken Sie im Dateisystem-Dock auf die zuvor gespeicherte Datei Sprite.tscn
und ziehen Sie sie auf die Node2D, um sie zu instanziieren.

We want to add another node as a sibling of the Sprite. To do so, right-click on Node2D and select Add Child Node.

Search for the Button node type and add it.

Der Knoten ist standardmäßig klein. Klicken und ziehen Sie am unteren rechten Ziehpunkt der Schaltfläche, um die Größe zu ändern.

If you don't see the handles, ensure the select tool is active in the toolbar.

Klicken und ziehen Sie den Knopf, um ihn näher an das Sprite zu bringen.
You can also write a label on the Button by editing its Text property in the Inspector.

Your scene tree and viewport should look like this.

Save your newly created scene. You can then run it with F6.
Connecting a signal in the editor¶
Here, we want to connect the Button's "pressed" signal to our Sprite, and we want to call a new function that will toggle its motion on and off. We need to have a script attached to the Sprite node, which we do from the previous lesson.
You can connect signals in the Node dock. Select the Button node and, on the right side of the editor, click on the tab named "Node" next to the Inspector.

The dock displays a list of signals available on the selected node.

Double-click the "pressed" signal to open the node connection window.

There, you can connect the signal to the Sprite node. The node needs a receiver method, a function that Godot will call when the Button emits the signal. The editor generates one for you. By convention, we name these callback methods "_on_NodeName_signal_name". Here, it'll be "_on_Button_pressed".
Bemerkung
Man kann zweierlei Modi verwenden, um Signale über das Node-Dock zu verbinden. Der einfache Modus erlaubt ausschließlich die Verbindung zu Knoten mit dazugehörigem Script und erstellt in diesem eine neue Callback-Funktion.

Die fortgeschrittene Ansicht erlaubt die Anbindung an jeden Knoten und jede native Funktion, das Hinzufügen von Argumenten zur Callback-Funktion und das Setzen von Optionen. Dieser Modus lässt sich über das Anwählen der entsprechenden Schaltfläche rechts unten im Fenster umschalten.
Drücke auf die Verbindungsschaltfläche, um die Signalverbindung zu vervollständigen und in den Arbeitsbereich des Skriptes zu wechseln.

Wenn man auf das Symbol klickt öffnet sich ein Fenster und zeigt Informationen über die Verbindung an. Diese Eigenschaft ist nur verfügbar, wenn Knoten im Editor verbunden werden.

Lassen Sie uns die Zeile im Code mit dem pass
Schlüsselwort durch Code ersetzen, welcher die Bewegung des Nodes umschaltet.
Unser Sprite lässt sich dank des Codes in der _process()
-Funktion bewegen. Godot stellt eine Methode bereit, um den Ablauf zu aktivieren und zu deaktivieren: Node.set_process(). Eine weitere Methode der Node-Klasse, is_processing()
, gibt true
zurück, falls die Ausführung aktiv ist. Man kann diesen Wert über das Schlüsselwort not
umdrehen.
func _on_Button_pressed():
set_process(not is_processing())
Diese Funktion schaltet die Ausführung um und die Bewegung des Symbols beim Drücken der Knopfes entsprechend ein und aus.
Bevor man das Spiel ausprobiert, muss die _process()
-Funktion vereinfacht werden, um den Knoten automatisch zu bewegen und nicht auf die Eingabe des Anwenders warten zu müssen. Daher ersetzen wir ihren Code durch den folgenden, der bereits in er vorletzten Lektion vor kam:
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
Der komplette Szenenbaum Sprite.gd sollte wie folgt aussehen.
extends Sprite
var speed = 400
var angular_speed = PI
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
func _on_Button_pressed():
set_process(not is_processing())
Starte Sie die Szene und klicken Sie auf die Schaltfläche um das Sprite zum Laufen und Halten zu bringen.
Ein Signal über Code verbinden¶
Man kann Signale auch über den Code erzeugen anstelle den Editor zu verwenden. Dies ist notwendig, falls man Notes oder Szenen innerhalb eines Skriptes erzeugen möchte.
Wir verwenden an dieser Stelle einen anderen Node. Godot besitzt einen Knoten Timer, der hilfreich ist, um Skill-Cooldown-Zeiten, das Nachladen von Waffen oder anderes zu implementieren.
Head back to the 2D workspace. You can either click the "2D" text at the top of the window or press Ctrl + F1 (Alt + 1 on macOS).
In the Scene dock, right-click on the Sprite node and add a new child node. Search for Timer and add the corresponding node. Your scene should now look like this.

Bei angewähltem Timer-Knoten lässt sich im Inspektor die Autostart-Eigenschaft anwählen.

Drücken Sie auf das Skript-Symbol neben dem Sprite und springen Sie zurück in den Script-Arbeitsbereich.

Es müssen zwei Schritte ausgeführt werden, um die Knoten im Code zu verbinden:
Ermittelt den Verweis auf den Timer des Sprites.
Rufen Sie die
connect()
-Methode des Timers auf.
Bemerkung
Um das Signal im Quellcode anzubinden, ruft man die connect()
-Methode des Knotens auf, dessen Signal man erwartet. In diesem Fall wird das "timeout"-Signal des Timers erwartet.
We want to connect the signal when the scene is intantiated, and we can do that using the Node._ready() built-in function, which is called automatically by the engine when a node is fully instantiated.
Um die Referenz auf einen Knoten zu erhalten, der sich in Relation zum aktuellen befindet, verwendet man die Methode Node.get_node(). Die Referenz kann in einer Variablen gespeichert werden.
func _ready():
var timer = get_node("Timer")
Die Funktion get_node()
ermittelt den Knoten an Hand des Namens der Sprite-Kinderknoten. Wenn man den Timer beispielsweise in "BlinkingTimer" umbenannt hat, muss man den Aufruf in get_node("BlinkingTimer")
abändern.
Nun kann man den Timer in der _ready()
-Funktion zum Sprite anbinden.
func _ready():
var timer = get_node("Timer")
timer.connect("timeout", self, "_on_Timer_timeout")
Die Zeile liest sich wie folgt: Das Signal "timeout" von Timer wird mit dem Knoten verbunden, dem das Script gehört (self
). Sobald der Timer "timeout" sendet, soll die Funktion "_on_Timer_timeout" angestoßen werden, die gerade definiert wurde. Diese wird jetzt am Ende des Skriptes ergänzt, um die Sichtbarkeit des Sprites umschalten zu können.
func _on_Timer_timeout():
visible = not visible
Die Eigenschaft visible
ist ein boolean-Wert, der festlegt, ob ein Knoten sichtbar ist. Die Zeile visible = not visible
wechselt zwischen sichtbar und unsichtbar hin und her. Wenn visible
auf true
war wird es auf false
gestetzt und umgekehrt.
Complete script¶
That's it for our little moving and blinking Godot icon demo!
Here is the complete Sprite.gd
file for reference.
extends Sprite
var speed = 400
var angular_speed = PI
func _ready():
var timer = get_node("Timer")
timer.connect("timeout", self, "_on_Timer_timeout")
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
func _on_Button_pressed():
set_process(not is_processing())
func _on_Timer_timeout():
visible = not visible
Benutzerdefinierte Signale¶
Bemerkung
This section is a reference on how to define and use your own signals, and does not build upon the project created in previous lessons.
Man kann mehrere verschiedene Signale innerhalb eines Skriptes definieren. Möchte man beispielsweise einen "Game Over"-Bildschirm anzeigen, sobald der Gesundheitswert des Spielers auf Null gesunken ist, kann man ein Signal namens "died" oder "health_depleted" definieren, das angestoßen wird, sobald der Gesundheitswert auf Null gesetzt wurde.
extends Node2D
signal health_depleted
var health = 10
Bemerkung
Da sämtliche Signale Ereignisse repräsentieren, die gerade erst stattfanden, verwendet man üblicherweise die Vergangenheitsform des Verbes für deren Namen.
Diese Signale arbeiten genau so wie native: Sie erscheinen im Node-Tab und man kann sie wie alle anderen anbinden.

To emit a signal in your scripts, call emit_signal()
.
func take_damage(amount):
health -= amount
if health <= 0:
emit_signal("health_depleted")
A signal can optionally declare one or more arguments. Specify the argument names between parentheses:
extends Node
signal health_changed(old_value, new_value)
Bemerkung
Die Signal-Argumente werden oben im Bearbeitungs-Node-Dock auftauchen, und Godot kann diese nutzen, um Aufruf-Funktionen für Sie zu generieren. Allerdings kann man immer noch jede beliebige Anzahl von Argumenten aufrufen, wenn man Signale aufruft. Es ist also in der Hand der Person, diese richtigen Werte aufzurufen.
To emit values along with the signal, add them as extra arguments to the
emit_signal()
function:
func take_damage(amount):
var old_health = health
health -= amount
emit_signal("health_changed", old_health, health)
Zusammenfassung¶
Jeder Knoten in Godot sendet Signale, wenn etwas spezielles passiert, beispielsweise beim Drücken eines Buttons. Andere Knoten können sich mit definierten Signalen verbinden und so auf die ausgewählten Ereignisse reagieren.
Signale können vielfältig verwendet werden. Man kann auf einen Knoten reagieren, der gerade die Spielwelt betritt oder verlässt, auf eine Kollision, darauf dass eine Spielfigur einen bestimmten Bereich betritt oder verlässt, darauf dass ein Element seine Größe verändert und vieles mehr.
For example, an Area2D representing a coin emits a
body_entered
signal whenever the player's physics body enters its collision
shape, allowing you to know when the player collected it.
In the next section, Your first 2D game, you'll create a complete 2D game and put everything you learned so far into practice.