Im Game Development muss oft nachvollzogen werden können, wann sich zwei Objekte im Spiel schneiden oder in Kontakt kommen. Dies wird als Collision Detection bezeichnet. Wenn eine Kollision erkannt wird, möchten wir normalerweise, dass etwas passiert. Dies wird als Collision Response bezeichnet.
Godot bietet eine Reihe von Kollisionsobjekten in 2D und 3D an, um sowohl Collision Detection als auch Response zu ermöglichen. Der Versuch, zu entscheiden, welche man für sein Projekt verwenden soll, kann verwirrend sein. Sie können Probleme vermeiden und die Entwicklung vereinfachen, wenn Sie verstehen, wie jedes einzelne funktioniert und was seine Vor- und Nachteile sind.
In diesem Leitfaden werden Sie lernen:
- Godot`s vier Kollisionsobjekttypen
- Wie jedes Kollisionsobjekt funktioniert
- Wann und warum sollte man einen Typ über einen anderen wählen.
Hinweis: Die Beispiele in diesem Dokument verwenden 2D-Objekte. Jedes 2D Physics Objekt und jede Kollisionsform hat ein direktes Äquivalent zu 3D und funktioniert in den meisten Fällen ähnlich.
Kollisionsobjekte.
Godot bietet vier Arten von physikalischen Körpern an, die CollisionObject2D erweitern:
- Area2D
Area2D-Nodes bieten Erkennung und Einfluss. Sie können erkennen, wann sich Objekte überlappen und Signale aussenden, wenn Körper ein- und austreten. Ein Area2D kann auch verwendet werden, um physikalische Eigenschaften wie Schwerkraft oder Dämpfung in einem definierten Bereich zu übersteuern.
Die anderen drei Körper reichen von PhysicsBody2D aus:
- StaticBody2D
Ein statischer Körper ist ein Körper, der nicht von der Physik-Engine bewegt wird. Sie nimmt an der Collision Detection teil, bewegt sich aber nicht als Reaktion auf die Kollision. Sie werden am häufigsten für Objekte verwendet, die Teil der Umgebung sind oder kein dynamisches Verhalten aufweisen müssen.
- RigidBody2D
Dies ist der Node, der die simulierte 2D-Physik implementiert. Sie steuern einen RigidBody2D nicht direkt, sondern wenden Kräfte (Schwerkraft, Impulse etc.) auf ihn an und die Physics Machine berechnet die resultierende Bewegung.
- KinematicBody2D
Ein Körper, der Collision Detection bietet, aber keine Physics. Alle Bewegungs- und Kollisionsreaktionen müssen im Code implementiert werden.
Kollisionsformen.
Ein Physics Body kann beliebig viele Shape2D-Objekte als Children aufnehmen. Diese Formen werden verwendet, um die Kollisionsgrenzen des Objekts zu definieren und den Kontakt mit anderen Objekten zu erkennen.
Hinweis: Um Kollisionen zu erkennen, muss dem Objekt mindestens eine Shape2D zugeordnet sein.
Die gebräuchlichste Methode, eine Form zuzuweisen, ist das Hinzufügen einer CollisionShape2D oder CollisionPolygon2D als Child des Objekts. Diese Nodes ermöglichen es ihnen, die Form direkt im Arbeitsbereich des Editors zu zeichnen.
Achten Sie darauf, dass Sie ihre Kollisionsformen im Editor niemals skalieren. Die Eigenschaft „Scale“ im Inspektor sollte enthalten bleiben (1, 1). Wenn Sie die Größe der Kollisionsform ändern, sollten Sie immer die Size-Handles verwenden, nicht die Node2D-Scale-Handles. Die Skalierung einer Form kann zu einem unerwarteten Kollisionsverhalten führen.
Physics Process Callback.
Die Physics Engine kann mehrere Threads erzeugen, um die Leistung zu verbessern, so dass sie bis zu einem Vollbild der Verarbeitung der Physik verwendet werden kann. Aus diesem Grund ist der Wert der Zustandsvariablen eines Körpers, wie Position oder Lineargeschwindigkeit, für den aktuellen Frame möglicherweise nicht genau.
Um diese Ungenauigkeit zu vermeiden, sollte jeder Code, der auf die Eigenschaften eines Körpers zugreifen muss, im Callback Node._physics_process() ausgeführt werden, der vor jedem Physics-Schritt mit einer konstanten Bildrate (standardmäßig 60 mal pro Sekunde) aufgerufen wird.
Kollisionslayer und -masken.
Eines der mächtigsten, aber häufig missverstandenen Kollisionsmerkmale ist das Collision Layer System. Dieses System ermöglicht es ihnen, komplexe Interaktionen zwischen verschiedenen Objekten aufzubauen. Die Schlüsselbegriffe sind Ebenen und Masken. Jedes CollisionObject2D hat 20 verschiedene physikalische Layer, mit denen es interagieren kann.
Betrachten wir die einzelnen Eigenschaften nacheinander:
- collision_layer
Dies beschreibt die Layer, in denen das Objekt erscheint. Standardmäßig befinden sich alle Körper auf Layer 1.
- collision_mask
Hier wird beschrieben, welche Layer der Körper nach Kollisionen durchsucht: Wenn sich ein Objekt nicht in einer der Maskenlayer befindet, ignoriert der Körper es. Standardmäßig scannen alle Körper den Layer 1.
Diese Eigenschaften können per Code oder durch Bearbeitung im Inspektor konfiguriert werden.
Es kann schwierig sein, den Überblick darüber zu behalten, wofür Sie jede Ebene verwenden, so dass Sie es vielleicht nützlich finden, den von ihnen verwendeten Layer-Namen zuzuweisen. Namen können unter Projekteinstellungen > Layernamen vergeben werden.
Beispiel:
Du hast vier Nodetypen in deinem Spiel: Walls, Player, Enemy und Coin. Sowohl Player als auch Enemy sollten mit Walls kollidieren. Die Playernodes sollte Kollisionen mit Enemy und Coin erkennen, aber Enemy und Coin sollten sich gegenseitig ignorieren.
Benennen Sie zunächst die Layer 1-4 „Walls“, „Player“, „Enemy“, „Coin“ und platzieren Sie jeden Nodetyp über die Eigenschaft „Layer“ in seinem jeweiligen Layer. Legen Sie dann die Eigenschaft „Mask“ für jeden Node fest, indem Sie die Layer auswählen, mit denen er interagieren soll.
Area2D.
Area Nodes bieten Erkennung und Einfluss. Sie können erkennen, wann sich Objekte überlappen und Signale aussenden, wenn Körper ein- und austreten. Bereiche können auch verwendet werden, um physikalische Eigenschaften wie Schwerkraft oder Dämpfung in einem definierten Bereich zu übersteuern.
Es gibt 3 Hauptanwendungen für Area2D:
- Übergeordnete physikalische Parameter wie die Schwerkraft in einer bestimmten Region.
- Erkennen, wann andere Körper in eine Region eindringen oder aus ihr austreten oder welche Körper sich derzeit in einer Region befinden.
- Überprüfung anderer Bereiche auf Überlappung.
Standardmäßig erhalten die Bereiche auch Maus- und Touchscreen-Eingaben.
StaticBody2D.
Ein statischer Körper ist ein Körper, der nicht von der Physics Engine bewegt wird. Sie nimmt an der Collision Detection teil, bewegt sich aber nicht als Reaktion auf die Kollision. Es kann jedoch einem kollidierenden Körper Bewegung oder Rotation verleihen, als ob er sich bewegen würde, indem es seine Eigenschaften constant_linear_velocity_ und constant_angular_velocity verwendet.
StaticBody2D-Nodes werden am häufigsten für Objekte verwendet, die Teil der Umgebung sind oder kein dynamisches Verhalten aufweisen müssen.
Anwendungsbeispiele für StaticBody2D:
- Plattformen (einschließlich beweglicher Plattformen)
- Förderbänder
- Walls und andere Hindernisse
RigidBody2D.
Dies ist der Node, der die simulierte 2D-Physik implementiert. Sie steuern einen RigidBody2D nicht direkt. Stattdessen wenden Sie Kräfte darauf an und die Physics-Engine berechnet die resultierende Bewegung, einschließlich Kollisionen mit anderen Körpern und Kollisionsreaktionen wie Hüpfen, Drehen usw.
Sie können das Verhalten eines starren Körpers über Eigenschaften wie „Masse“, „Reibung“ oder „Aufprall“ ändern, die Sie im Inspektor einstellen können.
Das Verhalten des Körpers wird auch durch die Eigenschaften der Welt beeinflusst, wie in Projekteinstellungen > Physik festgelegt oder durch die Eingabe eines Area2D, das die globalen physikalischen Eigenschaften überschreibt.
Wenn ein starrer Körper in Ruhe ist und sich eine Zeit lang nicht bewegt hat, geht er in den Schlaf-Modus über. Ein Körper im Schlafmodus wirkt wie ein statischer Körper und seine Kräfte werden von der Physics-Engine nicht berechnet. Der Körper wacht auf, wenn Kräfte aufgebracht werden, entweder durch eine Kollision oder durch einen Code.
Rigid Body Modes:
Ein starrer Körper kann auf einen von vier Modi eingestellt werden:
- Starr – der Körper verhält sich wie ein physisches Objekt. Sie kollidiert mit anderen Körpern und reagiert auf die auf sie ausgeübten Kräfte. Dies ist der Standardmodus.
- Statisch – der Körper verhält sich wie ein StaticBody2D und bewegt sich nicht.
- Charakter – Ähnlich wie im „Starr“-Modus, aber der Körper kann sich nicht drehen.
- Kinematisch – der Körper verhält sich wie ein KinematicBody2D und muss per Code bewegt werden.
Verwendung von RigidBody2D.
Einer der Vorteile der Verwendung eines starren Körpers ist, dass viel Verhalten „kostenlos“ ohne Schreiben von Code möglich ist. Wenn Sie zum Beispiel ein Spiel im „Angry Birds“-Stil mit fallenden Blöcken machen würden, müssten Sie nur RigidBody2Ds erstellen und deren Eigenschaften anpassen. Das Stapeln, Fallen und Hüpfen wird von der Physics-Engine automatisch berechnet.
Wenn Sie jedoch eine gewisse Kontrolle über den Körper haben möchten, sollten Sie aufpassen – die Änderung der Position, der linearen Geschwindigkeit oder anderer physikalischer Eigenschaften eines starren Körpers kann zu unerwartetem Verhalten führen. Wenn Sie eine der physikalisch relevanten Eigenschaften ändern müssen, sollten Sie den Callback _integrate_forces() anstelle von _physics_process() verwenden. In diesem Callback haben Sie Zugriff auf den Physics2DDDirectBodyState des Körpers, der es ermöglicht, Eigenschaften sicher zu ändern und mit der Physics-Engine zu synchronisieren.
Hier zum Beispiel der Code für ein Raumschiff im Asteroiden-Stil:
GDScript:
C#:
Beachten Sie, dass wir die Eigenschaften linear_velocity oder angular_velocity nicht direkt einstellen, sondern Kräfte (Schub und Drehmoment) auf den Körper ausüben und die Physics-Engine die resultierende Bewegung berechnen lassen.
Wenn ein starrer Körper in den Schlaf-Modus geht, wird die Funktion _integrate_forces() nicht aufgerufen. Um dieses Verhalten zu umgehen, müssen Sie den Körper wach halten, indem Sie eine Kollision erzeugen, eine Kraft auf ihn ausüben oder die Eigenschaft can_sleep deaktivieren. Beachten Sie, dass dies einen negativen Einfluss auf die Performance haben kann.
Contact Reporting.
Standardmäßig behalten starre Körper den Überblick über Kontakte nicht, da dies eine große Menge an Speicherplatz erfordern kann, wenn viele Körper in der Szene sind. Um das Contact Reporting zu aktivieren, setzen Sie die Eigenschaft contacts_reported auf einen Wert ungleich Null. Die Kontakte können dann über Physics2DDirectBodyState.get_contact_count() und zugehörige Funktionen bezogen werden.
Das Contact Monitoring über Signale kann über die Eigenschaft contact_monitor aktiviert werden. Siehe RigidBody2D für die Liste der verfügbaren Signale.
KinematicBody2D.
KinematicBody2D-Körper erkennen Kollisionen mit anderen Körpern, sind aber nicht von physikalischen Eigenschaften wie Schwerkraft oder Reibung betroffen. Stattdessen müssen sie vom Benutzer über einen Code gesteuert werden. Die Physics-Engine bewegt einen kinematischen Körper nicht.
Beim Bewegen eines kinematischen Körpers sollten Sie dessen Position nicht direkt einstellen. Stattdessen verwenden Sie die Methoden move_and_collide() oder move_and_slide(). Diese Methoden bewegen den Körper eintlang eines bestimmten Vektors und er wird sofort gestoppt, wenn eine Kollision mit einem anderen Körper erkannt wird. Nach der Kollision des Körpers muss jede Kollisionsreaktion manuell kodiert werden.
Kinematische Collision Response.
Nach einer Kollision können Sie wollen, dass der Körper springt, an einer Wand entlang gleitet oder die Eigenschaften des von ihm getroffene Objekt ändert. Die Art und Weise, wie Sie mit der Kollisionsreaktion umgehen, hängt davon ab, mit welcher Methode Sie den KinematicBody2D bewegt haben.
move_and_collide
Bei Verwendung von move_and_collide() gibt die Funktion ein KinematicCollision2D-Objekt zurück, das Informationen über die Kollision und den kollidierenden Körper enthält. Aus diesen Informationen können Sie die Antwort ermitteln.
Zum Beispiel, wenn Sie den Punkt im Raum finden wollen, an dem die Kollision stattgefunden hat:
GDScript:
C#:
Oder um vom kollidierenden Objekt abzuprallen:
GDScript:
C#:
move_and_slide
Sliding ist eine häufige Kollisionsreaktion. Stellen Sie sich einen Spieler vor, der sich in einem Top-Down-Spiel entlang von Wänden bewegt oder in einem Platformer auf und ab läuft. Während es möglich ist, diese Antwort nach der Verwendung von move_and_collide() selbst zu kodieren, bietet move_and_slide() eine komfortable Möglichkeit, Gleitbewegungen zu implementieren, ohne viel Code zu schreiben.
Move_and_slide() bezieht den Zeitschritt automatisch in seine Berechnung ein, daher sollten Sie den Velocity-Vektor nicht mit dem Delta multiplizieren.
Verwenden Sie beispielsweise den folgenden Code, um einen Charakter zu erstellen, der den Boden (einschließlich der Hänge) entlang gehen und springen kann, wenn er auf dem Boden steht:
GDScript:
C#:
Vielen Dank für ihren Besuch.