Kollisionserkennung

Nachdem wir unseren Sprite2D mit einem Script zum Rotieren gebracht und ihm eine grundlegende Bewegung über Input Actions verliehen haben, ist es Zeit für den nächsten wichtigen Schritt: Kollisionserkennung.

In den meisten Spielen müssen Objekte erkennen, wann sie sich berühren oder überlappen. Das ist nötig für Dinge wie:

  • Unser Player stößt gegen eine Wand.
  • Eine Kugel trifft einen Gegner.
  • Unser Player sammelt einen Gegenstand auf.
  • Ein Charakter tritt auf eine Druckplatte.

Godot handhabt Kollisionen und Physik mit speziellen Physics Bodies Nodes. Diese Nodes haben die Fähigkeit, mit anderen Physik-Körpern zu interagieren.


Die wichtigsten 2D Physics Body Nodes

Die wichtigsten 2D Physics Body Nodes sind:

  • StaticBody2D: Für Objekte, die sich nicht bewegen sollen (Wände, Boden, unbewegliche Hindernisse). Sie reagieren auf Kollisionen, bewegen sich aber selbst nicht.
  • RigidBody2D: Für Objekte, die komplett von der Physik-Engine simuliert werden (z.B. eine Kiste, die fällt, ein Ball, der rollt). Wir steuern sie nicht direkt über die Position, sondern über Kräfte oder Impulse.
  • CharacterBody2D: Speziell für von Spieler:innen gesteuerte Charaktere entwickelt. Wir steuern die Bewegung direkt (wie wir es tun), und der Body kümmert sich darum, auf Kollisionen mit StaticBody2Ds oder RigidBody2Ds zu reagieren (z.B. stoppen vor einer Wand, an einer Schräge entlangrutschen).
  • Area2D: Dient nicht für solide Kollisionen, sondern nur zur Erkennung von Überlappungen (Detection). Nützlich für Trigger-Zonen oder das Einsammeln von Objekten (wenn der Spieler:in eine Area2D betritt, kann etwas passieren).

Ein Physics Body Node allein hat noch keine Form für die Kollision. Du musst ihm Child Nodes hinzufügen, die die Kollisionsform definieren. Das sind meist CollisionShape2D (mit einer einfachen Form wie Rechteck, Kreis, Kapsel) oder CollisionPolygon2D (für komplexere, polygonale Formen).

Da unser Sprite ein vom Spieler:in gesteuerter Charakter werden soll, ist CharacterBody2D der am besten geeignete Node. Wir werden die Scene leicht umbauen müssen, um ihn als Root zu verwenden und unsere Bewegung in seinem Script umzusetzen. Der Vorteil: CharacterBody2D hat eingebaute Funktionen (move_and_slide), die Bewegung und Kollisionsreaktion in einem Schritt erledigen.


Schritt 1: Eine neue Scene für den Player erstellen

Es ist best-practice, den Spieler:in (und eigentlich alle Objekte) in einer eigenen Scene zu definieren und diese dann in der Haupt-Level-Scene zu instanziieren.

  1. Gehe im Menü auf Scene -> New Scene (Strg + N).
  2. Klicke auf „Other Node“ und wähle CharacterBody2D als Root Node und klicke Create.
  3. Benenne den Root Node im Scene Dock um zu Player (Rechtsklick auf den Node -> Rename, oder F2 drücken).
  4. Speichere diese neue Scene: Scene -> Save Scene (Strg + S). Nenne sie z.B. player.tscn und speichere sie im Projekt-Root (oder lege einen neuen Ordner scenes an und speichere sie dort, was später ordentlicher ist – ich gehe im Folgenden davon aus).

Schritt 2: Visuelle Darstellung und Kollisionsform hinzufügen

Ein CharacterBody2D benötigt Child Nodes, um sichtbar zu sein und eine Kollisionsform zu erhalten. Wir fügen unserem Player jetzt einen Sprite2D für die Grafik und einen CollisionShape2D für die Kollision hinzu.

  1. Stelle sicher, dass du im Scene Dock den Player (CharacterBody2D) 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. Benenne ihn um in „Sprite“
  4. Wähle den neuen Sprite2D Node im Scene Dock aus. Gehe im Inspector zum Abschnitt „Texture“ und lade die Datei icon.svg (Godot-Logo) als seine Texture.
  5. Klicke erneut auf den Button „+“ (Child Node hinzufügen), während der Player Node noch ausgewählt ist.
  6. Suche in der Liste nach CollisionShape2D, wähle ihn aus und klicke Create. Benne ihn um in „Collision“
  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 RectangleShape2D“.
  9. Godot erstellt eine neue Form. Wechsel auf den Viewport (oben auf „2D“ klicken). Hier siehst du nun die Kollisionsform als blaues Rechteck im Zentrum des Godot-Logos. 
  10. Ziehe die Ankerpunkte des Rechtecks im Viewport so, dass die Kollisionsform das Godot-Logo umschließt. 

Schritt 3: Script an den CharacterBody2D anhängen

Jetzt hängen wir unser Script an den Player Node, um ihm Logik zu verleihen. Dieses Script wird die Bewegung des Players steuern und mit Kollisionen umgehen.

  1. Wähle im Scene Dock den Root Node Player (CharacterBody2D) aus.
  2. Suche im Inspector ganz unten nach „Script“ Klicke auf „<empty>“ und wähle „Load…“.
  3. Es öffnet sich ein Fenster. Suche das Script „Player.gd“ (vermutlich im Ordner scenes zu finden) und wähle es aus.
  4. Klicke „Open“.
  5. Neben dem Node „Player“ im Node-Dock erscheint nun eine Pergamentrolle. Klicke darauf und der Code-Editor öffnet sich.

Dein player.gd Script sollte jetzt so aussehen:

Aufräumen: Alte Dateien löschen

Da wir jetzt eine saubere player.tscn erstellt und unseren Player von Grund auf neu strukturiert haben, brauchen wir die alte Scene main_scene.tscn nicht mehr, die wir zuvor für unser Test-Sprite verwendet haben.

  1. Gehe ins Filesystem Dock (links unten).
  2. Klicke mit der rechten Maustaste auf main_scene.tscn und wähle „Delete“ und Bestätige die Löschung.

Schritt 4: Eine Welt-Scene erstellen und den Player instanziieren

Wir brauchen eine Scene, in der unser Player „lebt“ und mit anderen Objekten interagieren kann. Dies wird unsere Haupt-Spielwelt sein.

  1. Erstelle eine neue Scene (Strg + N).
  2. Klicke auf „Other Node“ und wähle einen generischen  Node als Root Node und klicke Create.
  3. Benenne den Root Node um in World.
  4. Speichere diese Scene als world.tscn im scene-Ordner.
  5. Instanziiere deine player.tscn Scene in die World-Scene (zieh die Datei player.tscn aus dem Filesystem Dock auf den World Node im Scene Dock). Du siehst jetzt Player als Child von World.
  6. Wechsel auf den Viewport (2D) und du siehst den Player in der World.

Schritt 5: Eine Wand hinzufügen (StaticBody2D)

Jetzt fügen wir ein unbewegliches Objekt hinzu, mit dem der Player kollidieren kann – eine Wand.

  1. Stelle sicher, dass du die Scene world.tscn geöffnet hast.
  2. Wähle im Scene Dock den Root Node World aus.
  3. Klicke auf den „+“ Button (Child Node hinzufügen).
  4. Suche und wähle StaticBody2D. Klicke Create. Benenne ihn um, z.B. in Wall.
  5. Füge dem Wall (StaticBody2D) einen CollisionShape2D als Child hinzu (wähle Wall, klicke „+“, suche CollisionShape2D). Nenne ihn „Collision“.
  6. Wähle den CollisionShape2D der Wand aus und erstelle im Inspector eine „New RectangleShape2D“ als Shape.
  7. Passe die Größe und Position dieser Wand-Kollisionsform im Viewport an, um eine Wand zu erstellen (z.B. einen langen, schmalen Block). Platziere sie so, dass dein Player später dagegen laufen kann.
  8. Um die Wand sichtbar zu machen,  wähle den Wall-Node (StaticBody2D) aus, füge einen ColorRect Node als Child hinzu. Passe die Größe des ColorRect im Inspector unter „Rect“ -> „Size“ an, damit er dieselbe Größe hat wie deine Kollisionsform. Wähle eine Farbe unter „Color“ im Inspector.
  9. Achtung: Hier kommt der frühere Hinweis zum Tragen, dass der Viewport gewöhnungsbedürftig in der Bedienung ist.
    • Zum Verschieben wähle „Move“ (W).
    • Wenn du die ganze Wall, samt Collision und ColorRect verschieben möchtest, achte darauf, dass im Node Dock Wall ausgewählt ist.
    • Zum Ändern der Größe, wähle das Objekt aus, dessen Größe du ändern möchtest und nutze den „Select Mode“ (Q).  „Scale“ (S) verhält sich für diesen Fall nicht gut.
    • Zum Prüfen: klicke auf ColorRect und prüfe im Inspector, dass die Position 0,0 ist
      • Ist das nicht der Fall, befindet sich die Wall – der Parent Node – woanders.
      • Setze ihn die Position auf 0,0 und verschiebe die Wall als Ganzes. Das erspart dir später Kopfschmerzen 😄
  10. Speichere die Scene world.tscn (Strg + S).

Schritt 6: Bewegungslogik in _physics_process verschieben und move_and_slide() nutzen

Um eine reibungslose Kollisionserkennung zu gewährleisten, ist es wichtig, die Physik- und Bewegungslogik in der Funktion _physics_process(delta) zu verarbeiten, da diese Funktion mit einer festen Frequenz (Physik-Tick) aufgerufen wird, unabhängig von der Framerate. Die _process(delta)-Funktion ist eher für visuelle Updates gedacht.

  1. Öffne dein player.gd Script.
  2. Schneide die Bewegungslogik (alles von var direction = ... bis position += ...) aus der _process(delta) Funktion aus.
  3. Füge die Funktion _physics_process(delta): hinzu (sie ist nicht standardmäßig im Template enthalten).
  4. Füge die Bewegungslogik (von var direction = Vector2.ZERO bis zur Zeile vor der alten position += ... Zeile) in die _physics_process(delta) Funktion ein.
  5. Füge am Ende der _physics_process(delta) Funktion die zwei wichtigen Zeilen hinzu: velocity = direction * speed und move_and_slide().

Dein player.gd Script sollte jetzt so aussehen:

Wichtiger Unterschied: velocity und move_and_slide()

Beachte, dass wir bei der Zuweisung zu velocity nicht mit delta multiplizieren (velocity = direction * speed). Die move_and_slide() Funktion macht das intern, basierend auf dem festen Physik-Tick. Sie nimmt die velocity Eigenschaft des CharacterBody2D und verwendet sie, um die Bewegung pro Frame zu berechnen, unter Berücksichtigung von Kollisionen und der delta-Zeit des Physik-Ticks.


Schritt 7: Speichern und Ausführen

Nun ist es an der Zeit, unsere Kollisionserkennung in Aktion zu sehen!

  1. Speichere dein player.gd Script (Strg + S).
  2. Stelle sicher, dass die Scene world.tscn als Haupt-Scene eingestellt ist. Wenn nicht, drücke F5 und wähle sie aus, oder stelle es in den Project Settings ein (Project -> Project Settings -> Application -> Run -> Main Scene).
  3. Führe das Projekt aus (F5).

Ergebnis:

Du siehst jetzt das rotierende Godot-Logo, das du mit den Tasten bewegen kannst. Wenn du versuchst, durch die Wand zu laufen, die du gezeichnet hast, stoppt dein Player davor. Die Rotation zeigt auch, dass die Kollisionen sauber an den Schnittkanten der Wall und des Players funktionieren.


Dein nächster Schritt

Puh, du hast einen großen Schritt gemacht! Du hast jetzt die Grundlagen der Kollisionserkennung in Godot verstanden und implementiert. Wir haben gelernt:

  • Die verschiedenen Physics Body-Typen und ihre Anwendungsbereiche.
  • Die Notwendigkeit von CollisionShape2D Nodes zur Definition der Kollisionsform.
  • Das Konzept des CharacterBody2D und die Funktion move_and_slide() für vom Spieler:in gesteuerte Bewegung mit Kollisionsbehandlung.
  • Wie man Szenen ineinander instanziiert, um komplexe Spielwelten aufzubauen.
  • Den entscheidenden Unterschied zwischen den Funktionen _process(delta) (für visuelle Updates) und _physics_process(delta) (für Physik und Bewegung).

Als Nächstes werden wir das Signalsystem von Godot detailliert beleuchten. Dieses leistungsstarke System ermöglicht es Nodes, miteinander zu kommunizieren, ohne voneinander wissen zu müssen – ein Schlüsselkonzept für sauberen und erweiterbaren Code in Godot.

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..