Area2D und Signale

Nachdem wir die Bewegung unseres Spielers oder unserer Spielerin und die solide Kollision mit einer Wand gemeistert haben, ist der nächste Schritt, die Interaktion mit Objekten zu lernen, die man einsammeln oder auslösen kann, ohne dass sie einen physisch blockieren.

Hierfür kommt ein anderer wichtiger Node-Typ ins Spiel: der Area2D. Im Gegensatz zu den Physics Bodies (CharacterBody2D, StaticBody2D, RigidBody2D), die auf solide Kollisionen reagieren (Stoßen, Abprallen), ist eine Area2D dafür da, Überlappungen zu erkennen. Sie blockiert nichts, sondern meldet nur, wenn ein anderer Physics Body oder eine andere Area2D in sie eintritt, sie verlässt oder sich darin befindet.

Um auf solche Ereignisse zu reagieren („Ein Body ist in mich eingetreten!“), nutzen wir ein fundamentales Konzept von Godot: Signale. Nodes können Signale aussenden, wenn etwas Bestimmtes passiert. Andere Nodes können sich mit diesen Signalen verbinden, um eine eigene Funktion auszuführen, wenn das Signal emittiert wird. Wenn du schonmal in anderen Programmiersprachen mit Events gearbeitet hast, kannst du dir sicher schon was darunter vorstellen.

Wir erstellen eine einfache „Münze“, die unser:e Spieler:in einsammeln kann.

Du wirst:

  • Eine neue Scene für ein wiederverwendbares Objekt erstellen (eine Münze).
  • Den Area2D Node verwenden.
  • Dem Area2D eine CollisionShape2D (für die Erkennung) und ein Sprite2D (für die Grafik) hinzufügen.
  • Ein Script an die Area2D anhängen.
  • Ein Signal (body_entered) des Area2D Nodes mit einer Funktion in unserem Script verbinden.
  • In dieser Funktion prüfen, ob der eintretende Body der Player ist und die Münze dann „sammeln“ (zunächst indem wir sie aus der Scene entfernen).

Schritt 1: Eine neue Scene für die Münze erstellen

Wir erstellen eine neue, eigenständige Scene für unsere Münze, die wir später beliebig oft in unserer World-Scene platzieren können:

  1. Gehe im Menü auf Scene -> New Scene (Strg + N).
  2. Klicke auf „Other Node“ und wähle Area2D als Root Node und klicke Create.
  3. Benenne den Root Node im Scene Dock um, z.B. zu Coin.
  4. Speichere diese neue Scene: Scene -> Save Scene (Strg + S). Nenne sie coin.tscn und speichere sie im scene-Ordner.

Schritt 2: Visuelle Darstellung und Kollisionsform der Münze hinzufügen

Wie schon beim Player, benötigt auch die Münze eine visuelle Darstellung und eine Form für die Kollisionserkennung.

  1. Stelle sicher, dass du im Scene Dock den Coin (Area2D) Node ausgewählt hast.
  2. Klicke auf den Button „+“ (Child Node hinzufügen) oberhalb des Scene Trees.
  3. Suche in der Liste nach Sprite2D, wähle ihn aus und klicke Create.
  4. Wähle den neuen Sprite2D Node im Scene Dock aus. Gehe im Inspector zum Abschnitt „Texture“ und lade eine Bild-Datei, die einem Coin ähnelt. Du kannst dir hier z.B. bei itch.io welche herunterladen
  5. Klicke erneut auf den Button „+“ (Child Node hinzufügen), während der Coin Node (Area2D) noch ausgewählt ist.
  6. Suche in der Liste nach CollisionShape2D, wähle ihn aus und klicke Create.
  7. Wähle den neuen CollisionShape2D Node im Scene Dock aus. Im Inspector siehst du die Eigenschaft „Shape“, die momentan „Empty“ ist.
  8. Klicke auf „<empty>“ neben „Shape“ und wähle im Dropdown-Menü „New CircleShape2D“. Eine Kreisform ist oft passender für Münzen.
  9. Godot erstellt eine neue Form. Klicke auf das neu erschienene CircleShape2D Symbol. Im Viewport siehst du nun die Kollisionsform als blauer Kreis.
  10. Ziehe die Ankerpunkte des Kreises im Viewport so, dass die Kollisionsform den Sprite2D (die Münze) umschließt. Du kannst auch den Radius im Inspector unter „Shape“ anpassen (dazu nochmal auf den gerade ausgewählten CircleShape2D klicken).
  11. Speichere die Scene coin.tscn (Strg + S).

Schritt 3: Script an die Münze anhängen und Signal verbinden

Nun kommt der Teil, der die Interaktion ermöglicht. Wir hängen ein Script an die Coin (Area2D) und verbinden ihr body_entered Signal, das ausgelöst wird, wenn ein PhysicsBody in die Area2D eintritt.

  1. Wähle im Scene Dock den Coin (Area2D) Node aus.
  2. Klicke auf den Button „Attach Script“ (Pergamentrolle mit Plus) oberhalb des Scene Trees (oder über das Kontextmenü).
  3. Stelle sicher, dass „Base Type“ auf Area2D steht und der Pfad coin.gd vorschlägt. Das „Template“ kann auf „Node“ bleiben.
  4. Klicke „Create“. Du siehst nun den Script Editor mit dem Basis-Template. 
  5. Ergänze class_name Coin extends Area2D am Anfang des Scripts. 
  6. Stelle sicher, dass der Coin Node im Scene Dock ausgewählt ist.
  7. Gehe ins Node Dock (dieses befindet sich standardmäßig rechts neben dem Inspector, unter den Reitern „Inspector“ und „Node“).
  8. Im Node Dock findest du eine Liste von Signalen, die der ausgewählte Node (Area2D) aussenden kann. Suche das Signal body_entered(body: PhysicsBody2D).
  9. Klicke doppelt auf dieses Signal oder wähle es aus und klicke unten im Node Dock auf „Connect…“.
  10. Ein Fenster „Connect a Signal“ öffnet sich. Im oberen Bereich siehst du das Signal (body_entered). Im unteren Bereich siehst du den Receiver. Stelle sicher, dass der Coin Node der Receiver ist (er ist bereits ausgewählt, da wir das Script an ihn gehängt haben). Die Methode, die generiert wird, sollte so aussehen: _on_body_entered.
  11. Klicke auf „Connect“. Godot erstellt automatisch die Funktion _on_body_entered(body) in deinem coin.gd Script und springt zum Script Editor.

Schritt 4: Kommunikation über Signale: Player sammelt die Münze ein

Um dem Player mitzuteilen, dass er eine Münze berührt hat und diese dann „einsammeln“ soll, nutzen wir eigene Signale. Das ist der Godot-Weg, um Nodes miteinander kommunizieren zu lassen, ohne dass sie direkt voneinander wissen müssen. Die Münze signalisiert lediglich, dass sie eingesammelt wurde. Unser Player kann dann auf dieses Signal hören und reagieren.

Hierfür werden wir:

  • Ein benutzerdefiniertes Signal in unserem coin.gd-Script deklarieren und aussenden.
  • Im player.gd-Script eine Funktion erstellen, die auf das Einsammeln reagiert.

Die Verbindung zwischen dem Münz-Signal und der Player-Funktion in unserer world.tscn herstellen, da die World-Scene sowohl den Player:in als auch die Münzen kennt.


Schritt 5: Den Player identifizieren (Gruppen)

Wenn ein anderes Objekt jetzt das CollisionShape2D unserer Münze berührt (in den Körper eintritt), wird das Signal body_entered gesendet und jeder Abonnement informiert. In unserem Fall wird die Methode _on_body_entered(body) aufgerufen. Die Variable body in der Funktion ist genau der Node, der gerade in unsere Münz-Area eingetreten ist.

Jetzt müssen wir nur noch sicherstellen, dass der body auch wirklich ein Player ist. Nicht das die Gegner uns alle Münzen klauen! Godot bietet ein sehr flexibles System, um Nodes zu identifizieren: Gruppen. Du kannst Nodes zu einer oder mehreren Gruppen hinzufügen. Dies ist der Weg, um Nodes nach ihrer „Rolle“ oder ihrem „Typ“ im Spiel zu kennzeichnen, anstatt sie direkt über ihren Namen oder ihren spezifischen Node-Typ zu identifizieren.

Den Player einer Gruppe hinzufügen:

  1. Öffne deine Scene player.tscn.
  2. Wähle im Scene Dock den Root Node Player (CharacterBody2D) aus.
  3. Gehe ins Node Dock (rechts neben dem Inspector). Dort findest du den Reiter „Groups“ (gleich neben „Signals„).
  4. Klicke auf das „+„. Es öffnet sich ein neues Fenster mit dem Namen „Create New Group“. Gib in das Feld „Name“ den Namen Player ein und klicke auf „Ok“.
    • Wichtig: Gruppennamen sind case-sensitive. Die Groß-Kleinschreibung ist später wichtig.
  5. Du siehst nun Player in der Liste der Gruppen, zu der dein Player gehört (am Haken zu erkennen).

Speichere die Scene player.tscn (Strg + S).


Schritt 6: Ein Signal in der Münze deklarieren und aussenden

Öffne dein coin.gd Script. Ganz oben im Script, unter extends Area2D, deklarieren wir ein neues Signal namens collected. Danach wird dieses Signal in der _on_Coin_body_entered-Funktion ausgesendet, bevor die Münze entfernt wird.

  • body.is_in_group("players") gibt true zurück, wenn der Node in der Gruppe „players“ ist, ansonsten false
  • signal collected: So deklarieren wir ein benutzerdefiniertes Signal. Es ist sinnnvoll, Signale am Anfang des Scripts zu deklarieren.
  • emit_signal("collected"): Ruft das Signal collected auf und informiert alle damit verbundenen Nodes.
  • queue_free() ist der Weg in Godot, um einen Node und alle seine Kinder sicher aus der Scene zu entfernen. Sie markiert den Node zur Löschung am Ende des aktuellen Frames. Das Löschen erst am Ende des Frames ist wichtig, um Fehler zu vermeiden, wenn der Node noch aktiv Operationen ausführt.

 Schritt 7: Eine Sammel-Funktion im Player erstellen

Öffne dein player.gd Script. Wir fügen eine einfache Funktion collect_coin() hinzu, die später Punkte hinzufügen, Sound abspielen oder andere Logik ausführen könnte, wenn der Player eine Münze einsammelt.


Schritt 8: Das Signal in der World-Scene verbinden

Damit unser Player auf das collected-Signal der Münze reagieren kann, müssen wir eine Verbindung herstellen. Die World-Scene ist der ideale Ort dafür, da sie sowohl unseren Player:in als auch die instanziierten Münzen kennt.

  1. Script an World-Scene anhängen:

    • Öffne world.tscn.
    • Wähle den Root Node World aus.
    • Klicke auf „Attach Script“ (Pergamentrolle mit Plus) oberhalb des Scene Trees.
    • Als „Base Type“ sollte Node stehen, und der Pfad world.gd. Klicke „Create“.
    • Speichere das world.gd Script (Strg + S).
  2. Verbindung im world.gd Script herstellen: Wir nutzen die _ready()-Funktion der World-Scene, da diese aufgerufen wird, sobald die Scene und alle ihre Kinder (inklusive Player:in und Münzen) bereit sind. Wir gehen alle Kinder der World durch, identifizieren Player:in und Münzen und stellen die Verbindungen her.

  • get_children(): Gibt eine Liste aller direkten Kinder dieses Nodes (der World) zurück. Darüber iterieren wir.
  • if child is Player: Da wir unserem Player-Script class_name Player gegeben haben, können wir hier direkt den Typ des Nodes prüfen. Das ist eine sehr robuste Methode.
  • child.collected.connect(player_node.collect_coin): Dies ist der Kern der Signalverbindung im Code. Es sagt: „Wenn das collected-Signal von diesem child (unserer Münze) ausgesendet wird, dann rufe die Funktion collect_coin() auf dem Player auf.“

Das Sammeln der Münze testen

Was haben wir gemacht, damit alles funktioniert? Eine ganze Menge:

  1. Player zur Gruppe „Player“ hinzugefügt
  2. Im Münz-Script signal collected definiert und emit_signal("collected") in der Funktion _on_body_entered(body) aufgerufen und die Münze entfernt.
  3. Im Player die Funktion func collect_coin() implementiert.
  4. Im World-Script alle Münzen mit dem Player verbunden.

Nun müssen wir nur noch die Münzen in der World platzieren.

  1. Öffne world.tscn. Platziere ein paar Instanzen unserer Münz-Scene im Level (zieh die gespeicherte coin.tscn Datei aus dem Filesystem Dock in den Viewport oder auf den World Node im Scene Dock). Passe ggf. die Größe an (im Inspector unter Node2D -> Transform -> Scale)
  2. Führe world.tscn aus (F5).

Jetzt solltest du die Münzen sehen, und wenn du mit deinem Player über eine drüberläufst, sollte sie verschwinden und sowohl „Münze berührt!“ (aus dem Coin-Script) als auch „Player hat die Münze erfolgreich gesammelt!“ (aus dem Player-Script) im Output Dock (unten im Editor) erscheinen.


Dein nächster Schritt

Sehr gut! Du hast jetzt erfolgreich interaktive Objekte erstellt, die auf Überlappungen reagieren, und dabei die Signal-Kommunikation in Godot genutzt. Wir haben gelernt:

  • Wie man Area2D Nodes nutzt, um Überlappungen zu erkennen.
  • Das Konzept von Signalen in Godot, wie man sie deklariert, aussendet und im Code verbindet, um auf Ereignisse zu reagieren.
  • Wie man Gruppen und class_name verwendet, um Nodes robust zu identifizieren.
  • Wie man durch das Verbinden von Signalen in einer übergeordneten Szene (der World) die Kommunikation zwischen verschiedenen instanziierten Szenen organisiert.

Demnächst werden wir weitere fortgeschrittene Anwendungen des Signalsystems beleuchten und beispielsweise ein simples UI-Element (HUD) erstellen, das die gesammelten Münzen anzeigt.

Für unseren nächsten Schritt bringen wir mit Animationen noch mehr Bewegung in die Szene.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..