Animation de personnage

Dans cette dernière leçon, nous utiliserons les outils d'animation intégrés de Godot pour faire flotter et battre nos personnages. Vous apprendrez à concevoir des animations dans l'éditeur et à utiliser le code pour donner vie à votre jeu.

image0

Nous commencerons par une introduction à l'utilisation de l'éditeur d'animation.

Utilisation de l'éditeur d'animation

Le moteur est livré avec des outils permettant de créer des animations dans l'éditeur. Vous pouvez ensuite utiliser le code pour les jouer et les contrôler au moment de l'exécution.

Ouvrez la scène du joueur, sélectionnez le nœud du joueur et ajoutez un nœud AnimationPlayer.

Le dock Animation apparaît dans le panneau inférieur.

image1

Il comporte une barre d'outils et le menu déroulant de l'animation en haut, un éditeur de piste au milieu qui est actuellement vide, et des options de filtre, d'accrochage et de zoom en bas.

Créons une animation. Cliquez sur Animation -> Nouveau.

image2

Nommez l'animation "float".

image3

Une fois que vous avez créé l'animation, la ligne de temps apparaît avec des chiffres représentant le temps en secondes.

image4

Nous voulons que l'animation commence à être lue automatiquement au début du jeu. Elle doit également tourner en boucle.

Pour ce faire, vous pouvez cliquer sur le bouton avec une icône "A+" dans la barre d'outils d'animation et sur les flèches de bouclage, respectivement.

image5

Vous pouvez également épingler l'éditeur d'animation en cliquant sur l'icône d'épinglage en haut à droite. Cela permet d'éviter qu'il ne se replie lorsque vous cliquez sur la fenêtre d'affichage et désélectionnez les nœuds.

image6

Définissez la durée de l'animation à "1,2" seconde dans le coin supérieur droit du dock.

image7

Vous devriez voir le ruban gris s'élargir un peu. Il vous montre le début et la fin de votre animation et la ligne bleue verticale est votre curseur temporel.

image8

Vous pouvez cliquer et faire glisser le curseur en bas à droite pour effectuer un zoom avant ou arrière sur la ligne de temps.

image9

L'animation du flottant

Avec le nœud animation player, vous pouvez animer la plupart des propriétés sur autant de nœuds que vous le souhaitez. Remarquez l'icône clé à côté des propriétés dans l'Inspecteur. Vous pouvez cliquer sur l'une d'entre elles pour créer une clé d'animation, une paire temps-valeur pour la propriété correspondante. La clé d'animation est insérée à l'endroit où se trouve votre curseur temporel dans la ligne de temps.

Insérons nos premières clés. Ici, nous allons animer à la fois la translation et la rotation du nœud Character.

Sélectionnez le Character et cliquez sur l'icône clé à côté de Translation dans l'Inspecteur. Faites de même pour Rotation Degrees.

image10

Deux pistes apparaissent dans l'éditeur avec une icône en forme de diamant représentant chaque clés d'animation.

image11

Vous pouvez cliquer et glisser sur les diamants pour les déplacer dans le temps. Déplacez la clé de translation sur 0.2 secondes et la clé de rotation sur 0.1 secondes.

image12

Déplacez le curseur temporel sur 0.5 secondes en cliquant et en faisant glisser sur la ligne de temps grise. Dans l'Inspecteur, réglez l'axe Y de Translation sur environ 0.65 mètres et l'axe X de Rotation Degrees sur 8.

image13

Créez une clé d'animation pour les deux propriétés et déplacez la clé de translation à 0.7 secondes en la faisant glisser sur la ligne de temps.

image14

Note

Un exposé sur les principes de l'animation dépasse le cadre de ce tutoriel. Notez simplement que vous ne voulez pas tout chronométrer et espacer uniformément. Les animateurs jouent plutôt avec le timing et l'espacement, deux principes fondamentaux de l'animation. Vous voulez décaler et contraster les mouvements de votre personnage pour qu'il semblent vivant.

Déplacez le curseur temporel à la fin de l'animation, à 1.2 secondes. Réglez la translation Y à environ 0.35 et la rotation X à -9 degrés. Une fois encore, créez une clé pour les deux propriétés.

Vous pouvez prévisualiser le résultat en cliquant sur le bouton lecture ou en appuyant sur Shift + D. Cliquez sur le bouton arrêt ou appuyez sur S pour arrêter la lecture.

image15

Vous pouvez voir que le moteur interpole entre vos clés d'animation pour produire une animation continue. Pour le moment, cependant, le mouvement semble très robotique. Cela est dû au fait que l'interpolation par défaut est linéaire, ce qui entraîne des transitions constantes, contrairement à la façon dont les êtres vivants se déplacent dans le monde réel.

Nous pouvons contrôler la transition entre les clés d'animation à l'aide de courbes d'assouplissement.

Cliquez et faites glisser autour des deux premières clés dans la ligne de temps pour les sélectionner.

image16

Vous pouvez modifier les propriétés des deux clés simultanément dans l'Inspecteur, où vous pouvez voir une propriété Easing.

image17

Cliquez et faites glisser sur la courbe, en la tirant vers la gauche. Cela cela fera un ease-out, c'est-à-dire un assouplissement rapide au départ qui ralentira lorsque le curseur temporel atteindra la clé d'animation suivante.

image18

Jouer l'animation pour voir la différence. La première moitié devrait déjà donner l'impression d'être un peu plus dynamique.

Appliquez un ease-out à la deuxième clé d'animation de la piste de la rotation.

image19

Faites l'inverse pour la deuxième clé d'animation de translation, en la faisant glisser vers la droite.

image20

Votre animation devrait ressembler à quelque chose comme ceci.

image21

Note

Les animations mettent à jour les propriétés des nœuds animés à chaque image, en remplaçant les valeurs initiales. Si nous animions directement le nœud Player, cela nous empêcherait de le déplacer dans le code. C'est là que le nœud Pivot s'avère utile : même si nous avons animé le Character, nous pouvons toujours déplacer et faire pivoter le Pivot et superposer les modifications à l'animation dans un script.

Maintenant si vous lancez au jeu, la créature du joueur flottera !

Si la créature est un peu trop proche du sol, vous pouvez déplacer le Pivot vers le haut pour la décaler.

Contrôler l'animation par le code

Nous pouvons utiliser du code pour contrôler la lecture de l'animation en fonction des entrées du joueur. Modifions la vitesse de l'animation lorsque le personnage se déplace.

Ouvrez le script du Player en cliquant sur l'icône de script à côté de lui.

image22

Dans _physics_process(), après la ligne où nous vérifions le vecteur direction, ajoutez le code suivant.

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

Ce code fait en sorte que lorsque le joueur se déplace, nous multiplions la vitesse de lecture par 4. Lorsqu'il s'arrête, nous la remettons à la normale.

Nous avons mentionné que le pivot pouvait superposer des transformations à l'animation. Nous pouvons faire en sorte que le personnage fasse un arc lorsqu'il saute en utilisant la ligne de code suivante. Ajoutez-la à la fin de _physics_process().

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

Animer les mobs

Voici une autre astuce intéressante avec les animations dans Godot : tant que vous utilisez une structure de nœuds similaire, vous pouvez les copier dans différentes scènes.

Par exemple, les scènes Mob et Player ont toutes deux un nœud Pivot et un nœud Character, de sorte que nous pouvons réutiliser les animations entre elles.

Ouvrez la scène Joueur, sélectionnez le nœud du lecteur d'animation et ouvrez l'animation "float". Ensuite, cliquez sur Animation -> Copie. Ensuite, ouvrez Mob.tscn et ouvrez son lecteur d'animation. Cliquez sur Animation -> Coller. C'est tout ; tous les monstres joueront maintenant l'animation flottante.

Nous pouvons modifier la vitesse de lecture en fonction de la random_speed de la créature. Ouvrez le script du Mob et à la fin de la fonction initialize(), ajoutez la ligne suivante.

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

Et avec cela, vous avez fini de coder votre premier jeu 3D complet.

Félicitations !

Dans la prochaine partie, nous récapitulerons rapidement ce que vous avez appris et vous donnerons quelques liens pour continuer à en apprendre davantage. Mais pour l'instant, voici l'intégralité des Player.gd et Mob.gd afin que vous puissiez vérifier votre code par rapport à eux.

Voici le script Player.

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()

Et le script Mob.

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()