2D Bewegungsübersicht

Einführung

Jeder Anfänger hat diese Frage: "Wie bewege ich meinen Charakter?" Abhängig vom Spielstil den Sie erstellen, haben Sie möglicherweise spezielle Anforderungen, aber im Allgemeinen basiert die Bewegung in den meisten 2D-Spielen auf einer kleinen Anzahl von Designs.

Wir benutzen :ref:`KinematicBody2D <class_KinematicBody2D>`in den Folgenden Beispielen, das Prinzip ist aber auch auf andere Node-Typen (Area2D,RigidBody2D) anwendbar.

Aufbau

Jedes der unten gennanten Beispiele nutzt das gleiche Szenen-Setup.

Öffnen Sie Projekt -> Projekteinstellungen und wählen Sie die Registerkarte "Input Map". Fügen Sie die folgenden Eingabeaktionen hinzu (siehe InputEvent für Details):

../../_images/movement_inputs.png

8-Wege Bewegung

In diesem Szenario soll der Benutzer die vier Richtungstasten (oben/links/unten/rechts oder W/A/S/D) drücken und sich in die ausgewählte Richtung bewegen. Der Name "8-Wege-Bewegung" kommt daher, dass sich der Spieler durch gleichzeitiges Drücken von zwei Tasten diagonal bewegen kann.

../../_images/movement_8way.gif

Fügen Sie dem kinematischen Körper ein Skript mit dem folgenden Code hinzu:

extends KinematicBody2D

export (int) var speed = 200

var velocity = Vector2()

func get_input():
    velocity = Vector2()
    if Input.is_action_pressed("right"):
        velocity.x += 1
    if Input.is_action_pressed("left"):
        velocity.x -= 1
    if Input.is_action_pressed("down"):
        velocity.y += 1
    if Input.is_action_pressed("up"):
        velocity.y -= 1
    velocity = velocity.normalized() * speed

func _physics_process(delta):
    get_input()
    velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;

    public Vector2 velocity = new Vector2();

    public void GetInput()
    {
        velocity = new Vector2();

        if (Input.IsActionPressed("right"))
            velocity.x += 1;

        if (Input.IsActionPressed("left"))
            velocity.x -= 1;

        if (Input.IsActionPressed("down"))
            velocity.y += 1;

        if (Input.IsActionPressed("up"))
            velocity.y -= 1;

        velocity = velocity.Normalized() * speed;
    }

    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        velocity = MoveAndSlide(velocity);
    }
}

In der Funktion get_input() überprüfen wir die vier Tastenereignisse und summieren sie auf, um den Geschwindigkeitsvektor zu erhalten. Dies hat den Vorteil, dass sich zwei entgegengesetzte Tasten gegenseitig aufheben, führt aber auch dazu, dass die diagonale Bewegung schneller ist, da die beiden Richtungen addiert werden.

Wir können das verhindern, wenn wir die Geschwindigkeit normalisieren, d.h. wir setzen ihre Länge auf 1 und multiplizieren sie mit der gewünschten Geschwindigkeit.

Tipp

Wenn Sie noch nie Vektor-Mathematik verwendet haben oder eine Auffrischung benötigen, können Sie eine Erklärung der Vektorverwendung in Godot unter Vektormathematik einsehen.

Bemerkung

Wenn der obige Code nichts bewirkt, wenn Sie die Tasten drücken, überprüfen Sie, ob Sie die Eingabeaktionen korrekt eingerichtet haben, wie im Aufbau-Teil dieses Tutorials beschrieben.

Drehung + Bewegung

Diese Art der Bewegung wird manchmal als "Asteroids-Stil" bezeichnet, weil sie der Funktionsweise dieses klassischen Arcade-Spiels ähnelt. Durch Drücken von links/rechts wird die Figur gedreht, während sie durch Drücken von oben/unten vorwärts oder rückwärts in die jeweilige Richtung bewegt wird.

../../_images/movement_rotate1.gif
extends KinematicBody2D

export (int) var speed = 200
export (float) var rotation_speed = 1.5

var velocity = Vector2()
var rotation_dir = 0

func get_input():
    rotation_dir = 0
    velocity = Vector2()
    if Input.is_action_pressed("right"):
        rotation_dir += 1
    if Input.is_action_pressed("left"):
        rotation_dir -= 1
    if Input.is_action_pressed("down"):
        velocity = Vector2(-speed, 0).rotated(rotation)
    if Input.is_action_pressed("up"):
        velocity = Vector2(speed, 0).rotated(rotation)

func _physics_process(delta):
    get_input()
    rotation += rotation_dir * rotation_speed * delta
    velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;
    [Export] public float rotationSpeed = 1.5f;

    public Vector2 velocity = new Vector2();
    public int rotationDir = 0;

    public void GetInput()
    {
        rotationDir = 0;
        velocity = new Vector2();

        if (Input.IsActionPressed("right"))
            rotationDir += 1;

        if (Input.IsActionPressed("left"))
            rotationDir -= 1;

        if (Input.IsActionPressed("down"))
            velocity = new Vector2(-speed, 0).Rotated(Rotation);

        if (Input.IsActionPressed("up"))
            velocity = new Vector2(speed, 0).Rotated(Rotation);

        velocity = velocity.Normalized() * speed;
    }

    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        Rotation += rotationDir * rotationSpeed * delta;
        velocity = MoveAndSlide(velocity);
    }
}

Hier haben wir zwei neue Variablen hinzugefügt, um unsere Drehrichtung und Geschwindigkeit zu verfolgen. Auch hier gilt: Wenn Sie beide Tasten gleichzeitig drücken, wird keine Rotation erzeugt. Die Drehung wird direkt auf die Eigenschaft rotation des Körpers angewendet.

Um die Geschwindigkeit zu setzen, verwenden wir die Methode Vector2.rotated(), so dass sie in die gleiche Richtung wie der Körper zeigt. rotated() ist eine nützliche Vektorfunktion, die Sie in vielen Situationen verwenden können, in denen Sie sonst trigonometrische Funktionen anwenden müssten.

Drehung + Bewegung (Maus)

Dieser Bewegungsstil ist eine Variation des Vorherigen. Diesmal wird die Richtung statt über die Tastatur über die Mausposition vorgegeben. Der Charakter "schaut" immer auf den Mauszeiger. Die Vorwärts-/Rückwärts-Eingänge bleiben jedoch gleich.

../../_images/movement_rotate2.gif
extends KinematicBody2D

export (int) var speed = 200

var velocity = Vector2()

func get_input():
    look_at(get_global_mouse_position())
    velocity = Vector2()
    if Input.is_action_pressed("down"):
        velocity = Vector2(-speed, 0).rotated(rotation)
    if Input.is_action_pressed("up"):
        velocity = Vector2(speed, 0).rotated(rotation)

func _physics_process(delta):
    get_input()
    velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;

    public Vector2 velocity = new Vector2();

    public void GetInput()
    {
        LookAt(GetGlobalMousePosition());
        velocity = new Vector2();

        if (Input.IsActionPressed("down"))
            velocity = new Vector2(-speed, 0).Rotated(Rotation);

        if (Input.IsActionPressed("up"))
            velocity = new Vector2(speed, 0).Rotated(Rotation);

        velocity = velocity.Normalized() * speed;
    }

    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        velocity = MoveAndSlide(velocity);
    }
}

Hier benutzen wir die Methode Node2D look_at(), um den Spieler auf eine bestimmte Position zu richten. Ohne diese Funktion könnte man den gleichen Effekt erzielen, indem man den Winkel wie folgt einstellt:

rotation = get_global_mouse_position().angle_to_point(position)
var rotation = GetGlobalMousePosition().AngleToPoint(Position);

klicken und bewegen

Dieses letzte Beispiel verwendet nur die Maus, um den Charakter zu steuern. Wenn Sie auf den Bildschirm klicken, bewegt sich der Spieler zum Zielort.

../../_images/movement_click.gif
extends KinematicBody2D

export (int) var speed = 200

var target = Vector2()
var velocity = Vector2()

func _input(event):
    if event.is_action_pressed("click"):
        target = get_global_mouse_position()

func _physics_process(delta):
    velocity = position.direction_to(target) * speed
    # look_at(target)
    if position.distance_to(target) > 5:
        velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;

    public Vector2 target = new Vector2();
    public Vector2 velocity = new Vector2();

    public override void _Input(InputEvent @event)
    {
        if (@event.IsActionPressed("click"))
        {
            target = GetGlobalMousePosition();
        }
    }

    public override void _PhysicsProcess(float delta)
    {
        velocity = Position.DirectionTo(target) * speed;
        // LookAt(target);
        if (Position.DistanceTo(target) > 5)
        {
            velocity = MoveAndSlide(velocity);
        }
    }
}

Beachten Sie den distance_to()-Check, den wir vor der Bewegung durchführen. Ohne diesen Test würde der Körper beim Erreichen der Zielposition "zittern", da er sich leicht an der Position vorbei bewegt und versucht, sich zurück zu bewegen, nur um sich dabei ebenfalls zu weit zu bewegen und sich wieder nach vorn zu bewegen.

Wenn Sie die Zeile look_at() auskommentieren, wird der Körper auch so gedreht, dass er in seine Bewegungsrichtung zeigt, wenn Sie möchten.

Tipp

Diese Technik kann auch als Grundlage für ein "folgendes" Zeichen verwendet werden. Die target-Position kann die eines beliebigen Objekts sein, zu dem Sie sich bewegen möchten.

Zusammenfassung

Diese Codebeispiele können als Ausgangspunkt für Ihre eigenen Projekte hilfreich sein. Nutzen Sie sie gern, um mit ihnen zu experimentieren und um zu sehen, was Sie damit erstellen können.

Sie können dieses Beispielprojekt hier herunterladen: 2D_movement_demo.zip