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)

This style of movement is a variation of the previous one. This time, the direction is set by the mouse position instead of the keyboard. The character will always "look at" the mouse pointer. The forward/back inputs remain the same, however.

../../_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);
    }
}

Here we're using the Node2D look_at() method to point the player towards a given position. Without this function, you could get the same effect by setting the angle like this:

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

klicken und bewegen

This last example uses only the mouse to control the character. Clicking on the screen will cause the player to move to the target location.

../../_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);
        }
    }
}

Note the distance_to() check we make prior to movement. Without this test, the body would "jitter" upon reaching the target position, as it moves slightly past the position and tries to move back, only to move too far and repeat.

Uncommenting the look_at() line will also turn the body to point in its direction of motion if you prefer.

Tipp

This technique can also be used as the basis of a "following" character. The target position can be that of any object you want to move to.

Zusammenfassung

You may find these code samples useful as starting points for your own projects. Feel free to use them and experiment with them to see what you can make.

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