Die Animation des Charakters

In dieser letzten Lektion, werden wir Godots integrierten Animationswerkzeuge verwenden um unseren Charakter scheben und flattern zu lassen. Sie werden lernen, Animationen im Editor zu entwerfen und Code zu verwenden, um das Spiel lebendig zu gestalten.

image0

Wir beginnen mit einer Einführung in die Verwendung des Animationseditors.

Verwendung des Animationseditors

Die Engine verfügt über Werkzeuge zur Erstellung von Animationen im Editor. Sie können dann Code verwenden um diese während des Spiels abzuspielen und zu steuern.

Öffnen Sie die Spieler Szene, wählen Sie das Spieler Node und fügen Sie dann ein AnimationPlayer Node hinzu.

Das Animation Panel erscheint in dem unteren Bereich.

image1

Es enthält eine Symbolleiste und das Dropdown-Menü für Animationen im oberen Bereich, in der Mitte einen Spureditor, der derzeit leer ist und darunter Filter-, Einrast- und Zoomoptionen.

Lassen Sie uns nun eine Animation erstellen. Klicken Sie auf Animation -> Erstelle.

image2

Nennen Sie die Animation "float".

image3

Sobald Sie eine Animation erstellt haben, erscheint der Zeitstrahl mit Nummern, die Zeit in Sekunden angeben.

image4

Wir wollen, dass die Animation automatisch zu Beginn des Spiels startet. Außerdem soll sie in einer Schleife laufen.

Klicken Sie dazu jeweils ein Mal auf den Knopf mit dem "A+" Symbol in der Animations-Symbolleiste und auf den mit den Schleifenpfeilen.

image5

Sie können den Animationseditor auch anheften, indem Sie auf das Stecknadelsymbol in der oberen rechten Ecke klicken. Dies verhindert dass er sich zusammenklappt, wenn Sie auf das Ansichtsfenster klicken und die Auswahl der Nodes aufheben.

|image6|

Legen Sie die Animationsdauer auf 1.2 Sekunden in der oberen rechten Ecke des Panels fest.

|image7|

Sie sollten sehen, dass das graue Band etwas erweitert wird. Es zeigt Ihnen den Anfang und das Ende ihrer Animation und die Vertikale blaue Linie is ihr Zeitcursor.

|image8|

Durch das Bewegen des Schiebereglers oben rechts kann in der Zeitachse gezoomt werden.

|image9|

The float animation

Mit der Animationsplayer Node, können Sie fast alle Eigenschaften von beliebig vielen Nodes animieren. Beachten Sie das Schlüsselsymbol neben den Eigenschaften im Inspektor. Sie können auf ein beliebiges dieser Symbole klicken um ein Schlüsselbild zu erstellen, ein Zeit und Wertepaar für die entsprechende Eigenschaft. Das Schlüsselbild wird dort eingefügt wo sich Ihr Zeitcursor in dem Zeitstrahl befindet.

Fügen wir nun unsere ersten Schlüsselbilder ein. Hier werden wir sowhol die Translation (Verschiebung) als auch Drehung des Charakter Nodes animieren.

Wählen Sie das Charakter Node und klicken Sie auf das Schlüsselsymbol neben Translation in dem Inspektor. Machen Sie dasselbe für Rotation Degrees.

|image10|

Im Editor erscheinen zwei Spuren mit einem Rautensymbol für jedes Schlüsselbild.

|image11|

Sie können auf die Rauten klicken und ziehen, um sie in der Zeit zu verschieben. Bewegen Sie den Translationsschlüssel auf 0.2 Sekunden und den Rotationsschlüssel auf 0.1 Sekunden.

|image12|

Bewegen Sie Ihren Zeitcursor zu 0.5 Sekunden indem Sie das graue Segment der Zeitleiste anklicken und ziehen. Stellen Sie im Inspektor die Y-Achse der Translation auf etwa 0.65 Meter und die X-Achse der Rotation Degrees auf 8.

|image13|

Erstellen Sie ein Schlüsselbild für beide Eigenschaften und verschieben Sie den Translationsschlüssel zu 0.7 Sekunden indem Sie ihn über den Zeitstrahl ziehen.

|image14|

Bemerkung

Eine Lektion über die Prinzipien der Animation sprengt leider den Rahmen dieser Anleitung. Merken Sie sich einfach dass Sie nicht unbedingt alles gleichmäßig raümlich und zeitlich verteilen wollen. Stattdessen spielen Animatoren mit Timing und Abständen, zwei zentralen Animationsprinzipien. Sie wollen die Bewegungen Ihres Charakters versetzen und kontrastieren, damit er sich lebendig anfühlt.

Bewegen Sie den Zeitcursor nun zum Ende der Animation, bei 1.2 Sekunden. Setzen sie die Y-Translation auf etwa 0.35 und die X-Rotation auf -9. Erstellen Sie erneut ein Schlüsselbild für beide Eigenschaften.

Sie können eine Vorschau des Ergebnisses anzeigen indem Sie auf den "Play" Knopf (Pfeilsymbol das nach rechts zeigt) oben links in dem Animationseditor klicken, oder indem Sie Shift + D`drücken. Klicken Sie auf den "Stopp" Knopf (Viereck Symbol) oder drücken Sie :kbd:`S, um die Wiedergabe zu beenden.

|image15|

Wie Sie sehen können, interpoliert die Engine zwischen den Werten der Schlüsselbilder um eine kontinuierliche Animation zu erzeugen. Im Moment wirkt die Bewegung allerdings sehr Roboterhaft. Das liegt daran dass die Standardinterpolation Linear ist, was zu konstanten Übergängen führt, anders als bei lebendigen Dingen in der realen Welt.

Wir können die Übergänge zwischen Schlüsselbildern mit Hilfe von Easing-Kurven steueren.

Klicken und ziehen Sie um die ersten beiden Schlüsselbilder in dem Zeitstrahl um sie auszuwählen.

|image16|

Sie können die Eigenschaften beider Schlüsselbilder gleichzeitig in dem Inspektor bearbeiten, wo Sie die Eigenschaft Easing sehen können.

|image17|

Klicken Sie auf die Kürve und ziehen Sie an ihr nach links. Dadurch formt die Kurve einen "ease-out", was so viel bedeuted wie eine "Entspannung entgegen des Endes". Dadurch fängt der Übergang schnell an, wird aber über seinen Verlauf langsamer, bis er das nächste Schlüsselbild erreicht.

|image18|

Spielen Sie die Animation erneut ab um den Unterschied zu sehen. Die erste Hälfte er Animation sollte etwas schwungvoller sein.

Wenden Sie auf das zweite Schlüsselbild in dem Rotations Track einen Ease-Out an.

image19

Ziehen Sie den zweiten Translationsschlüssel in umgekehrter Weise nach rechts.

image20

Ihre fertige Animation sollte ungefähr so aussehen.

image21

Bemerkung

Animationen aktualisieren die Eigenschaften der animierten Nodes jeden Frame, was die ursprünglichen Werte überschreibt. Würden wir die Translation der Player Node direkt animieren, könnten wir den Spieler nicht mehr über Code bewegen. Hier kommt das Pivot Node ins Spiel: Obwohl wir den Charakter animieren, können wir den Pivot immer noch Bewegen und Drehen und so Änderungen von einem Skript mit der Animation kombinieren.

Wenn Sie jetzt das Spiel spielen, wird der Spieler Charakter schweben!

Wenn der Charakter zu nahe am Boden ist, können Sie den Pivot nach oben verschieben.

Steuerung der Animation im Code

Wir können Code verwenden um die Wiedergabe der Animation mit den Eingaben des Spielers steuern. Ändern wir die Geschwindigkeit der Animation wenn der Charakter sich bewegt.

Öffnen Sie das Skript von Player indem Sie auf das Skript-Symbol neben der Node im Szenenbaum klicken.

image22

Fügen Sie in _physics_process() nach der Zeile, in der wir den Vektor direction überprüfen, folgenden Code ein.

func _physics_process(delta):
    #...
    #if direction != Vector3.ZERO:
        #...
        $AnimationPlayer.playback_speed = 4
    else:
        $AnimationPlayer.playback_speed = 1

Dieser Code sorgt dafür dass wenn die Wiedergabegeschwindigkeit mit 4 multipliziert wird, wenn der Spieler sich bewegt. Wenn er anhält, setzen wir sie auf den Standardwert zurück.

Wir haben bereits erwähnt, das der Pivot benutzt werden kann um Transformationen mit denen von Animationen zu kombinieren. Mit der folgenden Codezeile können wir die Figur beim Springen einen Bogen machen lassen. Fügen Sie sie am ende von _physics_process() hinzu.

func _physics_process(delta):
    #...
    $Pivot.rotation.x = PI / 6 * velocity.y / jump_impulse

Die Gegner animieren

Hier ist ein weiterer netter Trick für Animationen in Godot: Solange Sie eine ähnliche Nodestruktur verwenden, können Sie dieselbe Animation in verschiedene Szenen kopieren.

Zum Beispiel haben sowohl die Mob als auch die Player Szene ein Pivot und ein Character node, also können wir die Animation swischen ihnen wiederverwenden.

Öffnen Sie die Spieler Szene, wählen Sie das Animation Player Node aus und öffnen Sie die "float" Animation. Klicken Sie als nächstes auf Animation -> Kopieren. Öffnen Sie Mob.tscn und öffnen Sie den dortigen Animation Player. Klicken Sie schließlich auf Animation -> Einfügen. Und das war's schon; alle Monster werden nun auch die Schwebe-Animation abspielen.

Wir können die Wiedergabegeschwindigkeit basierend auf der random_speed Eigenschaft der Mobs verändern. Öffnen Sie das Skript des *Mob*s und fügen Sie am Ende der initialize() Funktion die folgende Zeile ein.

func initialize(start_position, player_position):
    #...
    $AnimationPlayer.playback_speed = random_speed / min_speed

Und damit haben Sie ihr erstes komplettes 3D-Spiel fertig programmiert.

Herzlichen Glückwunsch!

In dem nächsten Teil werden wir das Gelernte noch einmal kurz zusammenfassen und Ihnen einige Links geben, damit Sie noch mehr lernen können. Aber erstmal sind hier nochmal die vollständigen Player.gd und Mob.gd Skripte damit Sie ihren Code mit ihnen vergleichen können.

Hier ist das Player Skript.

extends KinematicBody

# Emitted when the player was hit by a mob.
signal hit

# How fast the player moves in meters per second.
export var speed = 14
# The downward acceleration when in the air, in meters per second per second.
export var fall_acceleration = 75
# Vertical impulse applied to the character upon jumping in meters per second.
export var jump_impulse = 20
# Vertical impulse applied to the character upon bouncing over a mob in meters per second.
export var bounce_impulse = 16

var velocity = Vector3.ZERO


func _physics_process(delta):
    var direction = Vector3.ZERO

    if Input.is_action_pressed("move_right"):
        direction.x += 1
    if Input.is_action_pressed("move_left"):
        direction.x -= 1
    if Input.is_action_pressed("move_back"):
        direction.z += 1
    if Input.is_action_pressed("move_forward"):
        direction.z -= 1

    if direction != Vector3.ZERO:
        direction = direction.normalized()
        $Pivot.look_at(translation + direction, Vector3.UP)
        $AnimationPlayer.playback_speed = 4
    else:
        $AnimationPlayer.playback_speed = 1

    velocity.x = direction.x * speed
    velocity.z = direction.z * speed

    # Jumping
    if is_on_floor() and Input.is_action_just_pressed("jump"):
        velocity.y += jump_impulse

    velocity.y -= fall_acceleration * delta
    velocity = move_and_slide(velocity, Vector3.UP)

    for index in range(get_slide_count()):
        var collision = get_slide_collision(index)
        if collision.collider.is_in_group("mob"):
            var mob = collision.collider
            if Vector3.UP.dot(collision.normal) > 0.1:
                mob.squash()
                velocity.y = bounce_impulse

    $Pivot.rotation.x = PI / 6 * velocity.y / jump_impulse


func die():
    emit_signal("hit")
    queue_free()


func _on_MobDetector_body_entered(_body):
    die()

Und hier das Skript des *Mob*s.

extends KinematicBody

# Emitted when the player jumped on the mob.
signal squashed

# Minimum speed of the mob in meters per second.
export var min_speed = 10
# Maximum speed of the mob in meters per second.
export var max_speed = 18

var velocity = Vector3.ZERO


func _physics_process(_delta):
    move_and_slide(velocity)


func initialize(start_position, player_position):
    look_at_from_position(start_position, player_position, Vector3.UP)
    rotate_y(rand_range(-PI / 4, PI / 4))

    var random_speed = rand_range(min_speed, max_speed)
    velocity = Vector3.FORWARD * random_speed
    velocity = velocity.rotated(Vector3.UP, rotation.y)

    $AnimationPlayer.playback_speed = random_speed / min_speed


 func squash():
    emit_signal("squashed")
    queue_free()


func _on_VisibilityNotifier_screen_exited():
    queue_free()