Verwenden von KinematicBody2D¶
Einführung¶
Godot bietet mehrere Kollisionsobjekte an, um sowohl Kollisionserkennung als auch Reaktion zu ermöglichen. Der Versuch, zu entscheiden, welches für Ihr Projekt verwendet werden soll, kann verwirrend sein. Sie können Probleme vermeiden und die Entwicklung vereinfachen, wenn Sie verstehen, wie sie funktionieren und welche Vor- und Nachteile sie haben. In dieser Anleitung sehen wir uns den KinematicBody2D Node an und zeigen einige Beispiele für dessen Verwendung.
Bemerkung
In diesem Dokument wird davon ausgegangen, dass Sie mit den verschiedenen physikalischen Körpern von Godot vertraut sind. Bitte lesen Sie zuerst Physik Einleitung.
Was ist ein beweglicher Körper?¶
KinematicBody2D
dient zur Implementierung von Körpern, die über Code gesteuert werden. Kinematische Körper erkennen Kollisionen mit anderen Körpern, wenn sie sich bewegen, werden jedoch nicht von physikalischen Eigenschaften der Engine wie Schwerkraft oder Reibung beeinflusst. Dies bedeutet, dass Sie Code schreiben müssen, um ihr Verhalten zu erstellen, aber Sie haben auch eine genauere Kontrolle darüber, wie sie sich bewegen und reagieren.
Tipp
Ein KinematicBody2D kann durch die Schwerkraft und andere Kräfte beeinflusst werden, aber Sie müssen die Bewegung im Code berechnen. Die Physik-Engine bewegt keinen KinematicBody2D.
Bewegung und Kollisionen¶
Wenn Sie einen KinematicBody2D
verschieben, sollten Sie seine position
-Eigenschaft nicht direkt festlegen. Stattdessen verwenden Sie die Methoden move_and_collide()
or move_and_slide()
. Diese Methoden bewegen den Körper entlang eines bestimmten Vektors und stoppen sofort, wenn eine Kollision mit einem anderen Körper erkannt wird. Nachdem ein KinematicBody2D kollidiert ist, muss jede Kollisionsantwort manuell codiert werden.
Warnung
Sie sollten kinematische Körperbewegungen nur in der _physics_process()
Funktion ausführen.
Die beiden Bewegungsmethoden dienen unterschiedlichen Zwecken. Später in dieser Anleitung sehen Sie Beispiele für deren Funktionsweise.
move_and_collide
¶
Diese Methode verwendet einen Parameter: a Vector2, der die relative Bewegung des Körpers angibt. In der Regel ist dies Ihr Geschwindigkeitsvektor multipliziert mit dem Frame-Zeitschritt (Delta
). Wenn die Engine irgendwo entlang dieses Vektors eine Kollision feststellt, hört der Körper sofort auf sich zu bewegen. In diesem Fall gibt die Methode ein KinematicCollision2D Objekt zurück.
KinematicCollision2D
ist ein Objekt, das Daten über die Kollision und das kollidierende Objekt enthält. Mit diesen Daten können Sie Ihre Kollisionsantwort berechnen.
move_and_slide
¶
Die Methode move_and_slide()
soll die Kollisionantwort in dem allgemeinen Fall vereinfachen, in dem ein Körper entlang des anderen gleiten soll. Es ist zum Beispiel besonders nützlich bei Plattformspielen oder Top-Down-Spielen.
Tipp
move_and_slide()
berechnet automatisch die Frame-basierte Bewegung mit delta
. Multiplizieren Sie Ihren Geschwindigkeitsvektor nicht mit delta
, bevor Sie ihn an move_and_slide()
übergeben.
Zusätzlich zum Geschwindigkeitsvektor verwendet move_and_slide()
eine Reihe weiterer Parameter, mit denen Sie das Gleitverhalten anpassen können:
up_direction
- Standardwert:Vector2( 0, 0 )
Mit diesem Parameter können Sie festlegen, welche Oberflächen die Engine als Boden betrachten soll. Wenn Sie dies einstellen, können Sie die Methoden
is_on_floor()
,is_on_wall()
undis_on_ceiling()
verwenden um festzustellen, mit welcher Art von Oberfläche der Körper in Kontakt steht. Der Standardwert bedeutet, dass alle Oberflächen als Wände betrachtet werden.stop_on_slope
- Standardwert:false
Dieser Parameter verhindert, dass ein Körper im Stillstand die Hänge hinunterrutscht.
max_slides
- Standardwert:4
Dieser Parameter gibt die maximale Anzahl von Kollisionen an, bevor der Körper aufhört sich zu bewegen. Wenn Sie es zu niedrig einstellen, kann dies die Bewegung vollständig verhindern.
floor_max_angle
- Standardwert:0.785398
(in Radiant, entspricht45
Grad)Dieser Parameter ist der maximale Winkel, bevor eine Oberfläche nicht mehr als "Boden" betrachtet wird.
infinite_inertia
- Standardwert:true
Wenn dieser Parameter true
ist, kann der Körper RigidBody2D-Nodes verschieben (wobei deren Masse ignoriert wird), jedoch keine Kollisionen mit ihnen erkennen. Wenn es false
ist, kollidiert der Körper mit starren Körpern und stoppt.
move_and_slide_with_snap
¶
Diese Methode fügt move_and_slide()
einige zusätzliche Funktionen hinzu, indem der Parameter snap
hinzugefügt wird. Solange dieser Vektor mit dem Boden in Kontakt steht, bleibt der Körper an der Oberfläche haften. Beachten Sie, dass Sie daher das Einrasten deaktivieren müssen, beispielsweise beim Springen. Sie können hierfür entweder snap
auf Vector2.ZERO
setzen oder stattdessen move_and_slide()
verwenden.
Kollisionen erkennen¶
Bei Verwendung von move_and_collide()
gibt die Funktion direkt eine KinematicCollision2D
zurück, die Sie in Ihrem Code verwenden können.
Bei Verwendung von move_and_slide()
können mehrere Kollisionen auftreten, wenn die Antwort berechnet wird. Verwenden Sie zum Verarbeiten dieser Kollisionen get_slide_count()
und get_slide_collision()
:
# Using move_and_collide.
var collision = move_and_collide(velocity * delta)
if collision:
print("I collided with ", collision.collider.name)
# Using move_and_slide.
velocity = move_and_slide(velocity)
for i in get_slide_count():
var collision = get_slide_collision(i)
print("I collided with ", collision.collider.name)
// Using MoveAndCollide.
var collision = MoveAndCollide(velocity * delta);
if (collision != null)
{
GD.Print("I collided with ", ((Node)collision.Collider).Name);
}
// Using MoveAndSlide.
velocity = MoveAndSlide(velocity);
for (int i = 0; i < GetSlideCount(); i++)
{
var collision = GetSlideCollision(i);
GD.Print("I collided with ", ((Node)collision.Collider).Name);
}
Bemerkung
get_slide_count() zählt nur, wenn der Körper kollidiert ist und die Richtung geändert hat.
Siehe KinematicCollision2D für Details darüber, welche Kollisionsdaten zurückgegeben werden.
Welche Bewegungsmethode soll verwendet werden?¶
Eine häufige Frage von neuen Godot-Benutzern lautet: "Wie entscheiden Sie, welche Bewegungsfunktion verwendet werden soll?" Oft lautet die Antwort move_and_slide()
weil es "einfacher" ist, aber dies ist nicht unbedingt der Fall. Eine Möglichkeit sich das vorzustellen ist, dass move_and_slide()
ein Sonderfall und move_and_collide()
allgemeiner ist. Die folgenden zwei Codefragmente führen beispielsweise zu derselben Kollisionsantwort:

# using move_and_collide
var collision = move_and_collide(velocity * delta)
if collision:
velocity = velocity.slide(collision.normal)
# using move_and_slide
velocity = move_and_slide(velocity)
// using MoveAndCollide
var collision = MoveAndCollide(velocity * delta);
if (collision != null)
{
velocity = velocity.Slide(collision.Normal);
}
// using MoveAndSlide
velocity = MoveAndSlide(velocity);
Alles was Sie mit move_and_slide()
tun, kann auch mit move_and_collide()
ausgeführt werden, es kann jedoch etwas mehr Code erforderlich sein. Wie wir in den folgenden Beispielen sehen werden gibt es Fälle, in denen move_and_slide()
nicht die gewünschte Antwort liefert.
Im obigen Beispiel weisen wir die Geschwindigkeit zu, die move_and_slide()
in die Variable velocity
übergibt. Dies liegt daran, dass die Funktion die Geschwindigkeit intern neu berechnet, wenn das Zeichen mit der Umgebung kollidiert, um die Verlangsamung widerzuspiegeln.
Wenn Ihr Charakter beispielsweise auf den Boden gefallen ist, möchten Sie nicht, dass er aufgrund der Schwerkraft eine vertikale Geschwindigkeit erreicht. Stattdessen soll die vertikale Geschwindigkeit auf Null zurückgesetzt werden.
move_and_slide()
kann die Geschwindigkeit des kinematischen Körpers auch mehrmals in einer Schleife neu berechnen, da er den Charakter bewegt und standardmäßig bis zu fünf Mal kollidiert, um eine gleichmäßige Bewegung zu erzeugen. Am Ende des Prozesses gibt die Funktion die neue Geschwindigkeit des Charakters zurück, die wir in unserer Variablen velocity
speichern und im nächsten Frame verwenden können.
Beispiele¶
Um diese Beispiele in Aktion zu sehen, laden Sie das Beispielprojekt herunter: using_kinematic2d.zip
.
Bewegung und Wände¶
Wenn Sie das Beispielprojekt heruntergeladen haben, befindet sich dieses Beispiel in "BasicMovement.tscn".
Fügen Sie in diesem Beispiel einen KinematicBody2D
mit zwei untergeordneten Elementen hinzu: ein Sprite
und ein CollisionShape2D
. Verwenden Sie das Godot "icon.png" als Sprite-Textur (ziehen Sie es aus dem Dateisystem-Dock in die Textur-Eigenschaft des Sprite
). Wählen Sie in der Eigenschaft Shape von CollisionShape2D
die Option "NewRectangleShape2D" aus und passen Sie das Rechteck so an, dass es über das Sprite-Bild passt.
Bemerkung
Beispiele für die Implementierung von 2D-Bewegungsmuster finden Sie unter 2D Bewegungsübersicht.
Hängen Sie ein Skript an KinematicBody2D an und fügen Sie den folgenden Code hinzu:
extends KinematicBody2D
var speed = 250
var velocity = Vector2()
func get_input():
# Detect up/down/left/right keystate and only move when pressed.
velocity = Vector2()
if Input.is_action_pressed('ui_right'):
velocity.x += 1
if Input.is_action_pressed('ui_left'):
velocity.x -= 1
if Input.is_action_pressed('ui_down'):
velocity.y += 1
if Input.is_action_pressed('ui_up'):
velocity.y -= 1
velocity = velocity.normalized() * speed
func _physics_process(delta):
get_input()
move_and_collide(velocity * delta)
using Godot;
using System;
public class KBExample : KinematicBody2D
{
public int Speed = 250;
private Vector2 _velocity = new Vector2();
public void GetInput()
{
// Detect up/down/left/right keystate and only move when pressed
_velocity = new Vector2();
if (Input.IsActionPressed("ui_right"))
_velocity.x += 1;
if (Input.IsActionPressed("ui_left"))
_velocity.x -= 1;
if (Input.IsActionPressed("ui_down"))
_velocity.y += 1;
if (Input.IsActionPressed("ui_up"))
_velocity.y -= 1;
_velocity = _velocity.Normalized() * Speed;
}
public override void _PhysicsProcess(float delta)
{
GetInput();
MoveAndCollide(_velocity * delta);
}
}
Wenn Sie diese Szene ausführen, werden Sie sehen, dass move_and_collide()
wie erwartet funktioniert und den Körper entlang des Geschwindigkeitsvektors bewegt. Nun wollen wir sehen was passiert, wenn Sie einige Hindernisse hinzufügen. Fügen Sie ein StaticBody2D mit einer rechteckigen Kollisionsform hinzu. Zur besseren Sichtbarkeit können Sie ein Sprite oder ein Polygon2D verwenden oder "Sichtbare Kollisionsformen" im Menü "Debuggen" aktivieren.
Führen Sie die Szene erneut aus und versuchen Sie, sich in das Hindernis zu bewegen. Sie werden sehen, dass der KinematicBody2D
das Hindernis nicht durchdringen kann. Wenn Sie jedoch versuchen sich schräg in das Hindernis zu bewegen, werden Sie feststellen, dass das Hindernis wie Klebstoff wirkt - es fühlt sich an, als würde der Körper stecken bleiben.
Dies geschieht, weil es keine Kollisionsantwort gibt. move_and_collide()
stoppt die Bewegung des Körpers, wenn eine Kollision auftritt. Wir müssen jede gewünschte Antwort auf die Kollision codieren.
Versuchen Sie die Funktion in "move_and_slide (velocity)" zu ändern und erneut auszuführen. Beachten Sie, dass wir delta
aus der Geschwindigkeitsberechnung entfernt haben.
move_and_slide()
bietet eine Standardkollisionsantwort, bei der der Körper entlang des Kollisionsobjekts verschoben wird. Dies ist nützlich für sehr viele Spieltypen und kann schon alles sein was Sie benötigen, um das gewünschte Verhalten zu erreichen.
Abprallen/Reflektieren¶
Was ist, wenn Sie keine gleitende Kollisionsreaktion wünschen? In diesem Beispiel ("BounceandCollide.tscn" im Beispielprojekt) haben wir einen Charakter, der Geschosse abschießt und wir möchten, dass diese Geschosse von den Wänden abprallen.
In diesem Beispiel werden drei Szenen verwendet. Die Hauptszene enthält den Spieler und die Wände. Die Geschosse und die Wand sind separate Szenen, damit sie instanziiert werden können.
Der Spieler wird über die Tasten w und s für Vorwärts und Rückwärts gesteuert. Zum Zielen wird der Mauszeiger verwendet. Hier ist der Code für den Spieler mit move_and_slide()
:
extends KinematicBody2D
var Bullet = preload("res://Bullet.tscn")
var speed = 200
var velocity = Vector2()
func get_input():
# Add these actions in Project Settings -> Input Map.
velocity = Vector2()
if Input.is_action_pressed('backward'):
velocity = Vector2(-speed/3, 0).rotated(rotation)
if Input.is_action_pressed('forward'):
velocity = Vector2(speed, 0).rotated(rotation)
if Input.is_action_just_pressed('mouse_click'):
shoot()
func shoot():
# "Muzzle" is a Position2D placed at the barrel of the gun.
var b = Bullet.instance()
b.start($Muzzle.global_position, rotation)
get_parent().add_child(b)
func _physics_process(delta):
get_input()
var dir = get_global_mouse_position() - global_position
# Don't move if too close to the mouse pointer.
if dir.length() > 5:
rotation = dir.angle()
velocity = move_and_slide(velocity)
using Godot;
using System;
public class KBExample : KinematicBody2D
{
private PackedScene _bullet = (PackedScene)GD.Load("res://Bullet.tscn");
public int Speed = 200;
private Vector2 _velocity = new Vector2();
public void GetInput()
{
// add these actions in Project Settings -> Input Map
_velocity = new Vector2();
if (Input.IsActionPressed("backward"))
{
_velocity = new Vector2(-Speed/3, 0).Rotated(Rotation);
}
if (Input.IsActionPressed("forward"))
{
_velocity = new Vector2(Speed, 0).Rotated(Rotation);
}
if (Input.IsActionPressed("mouse_click"))
{
Shoot();
}
}
public void Shoot()
{
// "Muzzle" is a Position2D placed at the barrel of the gun
var b = (Bullet)_bullet.Instance();
b.Start(GetNode<Node2D>("Muzzle").GlobalPosition, Rotation);
GetParent().AddChild(b);
}
public override void _PhysicsProcess(float delta)
{
GetInput();
var dir = GetGlobalMousePosition() - GlobalPosition;
// Don't move if too close to the mouse pointer
if (dir.Length() > 5)
{
Rotation = dir.Angle();
_velocity = MoveAndSlide(_velocity);
}
}
}
Und der Code für das Geschoss:
extends KinematicBody2D
var speed = 750
var velocity = Vector2()
func start(pos, dir):
rotation = dir
position = pos
velocity = Vector2(speed, 0).rotated(rotation)
func _physics_process(delta):
var collision = move_and_collide(velocity * delta)
if collision:
velocity = velocity.bounce(collision.normal)
if collision.collider.has_method("hit"):
collision.collider.hit()
func _on_VisibilityNotifier2D_screen_exited():
queue_free()
using Godot;
using System;
public class Bullet : KinematicBody2D
{
public int Speed = 750;
private Vector2 _velocity = new Vector2();
public void Start(Vector2 pos, float dir)
{
Rotation = dir;
Position = pos;
_velocity = new Vector2(speed, 0).Rotated(Rotation);
}
public override void _PhysicsProcess(float delta)
{
var collision = MoveAndCollide(_velocity * delta);
if (collision != null)
{
_velocity = _velocity.Bounce(collision.Normal);
if (collision.Collider.HasMethod("Hit"))
{
collision.Collider.Call("Hit");
}
}
}
public void OnVisibilityNotifier2DScreenExited()
{
QueueFree();
}
}
Die Aktion erfolgt in _physics_process()
. Nach Verwendung von move_and_collide()
wird bei einer Kollision ein KinematicCollision2D
-Objekt zurückgegeben (andernfalls lautet die Rückgabe Nil
).
Wenn es eine zurückgegebene Kollision gibt, verwenden wir das normal
der Kollision, um die Geschwindigkeit velocity
des Geschosses mit der Vector2.bounce()
-Methode widerzuspiegeln.
Wenn das kollidierende Objekt (collider
) eine hit
Methode hat, rufen wir es auch auf. Im Beispielprojekt haben wir der Wand einen blinkenden Farbeffekt hinzugefügt, um dies zu demonstrieren.

Plattformer Bewegungen¶
Versuchen wir ein weiteres beliebtes Beispiel: den 2D-Plattformer. move_and_slide()
ist ideal um schnell einen funktionierenden Charakter-Controller zum Laufen zu bringen. Wenn Sie das Beispielprojekt heruntergeladen haben, finden Sie es in "Platformer.tscn".
In diesem Beispiel wird davon ausgegangen, dass Sie eine Ebene aus StaticBody2D
-Objekten haben. Sie können jede Form und Größe haben. Im Beispielprojekt verwenden wir Polygon2D um die Plattformformen zu erstellen.
Hier ist der Code für den Spielerkörper:
extends KinematicBody2D
export (int) var run_speed = 100
export (int) var jump_speed = -400
export (int) var gravity = 1200
var velocity = Vector2()
var jumping = false
func get_input():
velocity.x = 0
var right = Input.is_action_pressed('ui_right')
var left = Input.is_action_pressed('ui_left')
var jump = Input.is_action_just_pressed('ui_select')
if jump and is_on_floor():
jumping = true
velocity.y = jump_speed
if right:
velocity.x += run_speed
if left:
velocity.x -= run_speed
func _physics_process(delta):
get_input()
velocity.y += gravity * delta
if jumping and is_on_floor():
jumping = false
velocity = move_and_slide(velocity, Vector2(0, -1))
using Godot;
using System;
public class KBExample : KinematicBody2D
{
[Export] public int RunSpeed = 100;
[Export] public int JumpSpeed = -400;
[Export] public int Gravity = 1200;
Vector2 velocity = new Vector2();
bool jumping = false;
public void GetInput()
{
velocity.x = 0;
bool right = Input.IsActionPressed("ui_right");
bool left = Input.IsActionPressed("ui_left");
bool jump = Input.IsActionPressed("ui_select");
if (jump && IsOnFloor())
{
jumping = true;
velocity.y = JumpSpeed;
}
if (right)
velocity.x += RunSpeed;
if (left)
velocity.x -= RunSpeed;
}
public override void _PhysicsProcess(float delta)
{
GetInput();
velocity.y += Gravity * delta;
if (jumping && IsOnFloor())
jumping = false;
velocity = MoveAndSlide(velocity, new Vector2(0, -1));
}
}

Bei Verwendung von move_and_slide()
gibt die Funktion einen Vektor zurück, der die Bewegung darstellt, die nach dem Auftreten der Gleit-Kollision verblieben ist. Wenn Sie diesen Wert auf die Geschwindigkeit velocity
des Charakters zurücksetzen, können wir uns reibungslos auf und ab bewegen. Versuchen Sie velocity =
zu entfernen und sehen Sie was passiert, wenn Sie dies nicht tun.
Beachten Sie auch, dass wir Vector2(0, -1)
als Bodennormal hinzugefügt haben. Dieser Vektor zeigt gerade nach oben. Wenn der Charakter mit einem Objekt kollidiert, das diese Normalität aufweist, wird dies als Boden betrachtet.
Die Verwendung der Bodennormalen ermöglicht es uns mittels is_on_floor()
zu springen. Diese Funktion gibt erst nach einer Kollision mit move_and_slide()
ein true
zurück, wenn die Normalen des kollidierenden Körpers innerhalb von 45 Grad des angegebenen Bodenvektors liegen. Sie können den maximalen Winkel steuern, indem Sie floor_max_angle
einstellen.
Mit diesem Winkel können Sie auch andere Funktionen wie Wandsprünge implementieren, indem Sie beispielsweise is_on_wall()
verwenden.