Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Utiliser les AnimationTree

Introduction

With AnimationPlayer, Godot has one of the most flexible animation systems that you can find in any game engine. The ability to animate almost any property in any node or resource, as well as having dedicated transform, bezier, function calling, audio and sub-animation tracks, is pretty much unique.

Cependant, la prise en charge de la fusion de ces animations via AnimationPlayer est relativement limitée, car seul un temps de transition de fondu fixe peut être défini.

AnimationTree est un nouveau nœud introduit dans Godot 3.1 pour traiter les transitions avancées. Il remplace l'ancien AnimationTreePlayer, tout en ajoutant un grand nombre de fonctionnalités et de flexibilité.

Créer un AnimationTree

Avant de commencer, il faut préciser qu'un nœud AnimationTree ne contient pas ses propres animations. Il utilise plutôt les animations contenues dans un nœud AnimationPlayer. De cette façon, vous pouvez éditer vos animations (ou les importer depuis une scène 3D) comme d'habitude et ensuite utiliser ce nœud supplémentaire pour contrôler la lecture.

La façon la plus courante d'utiliser AnimationTree est dans une scène 3D. Lorsque vous importez vos scènes à partir d'un format d'échange 3D, elles seront généralement accompagnées d'animations intégrées (soit multiples, soit séparées depuis une grande à l'importation). A la fin, la scène Godot importée contiendra les animations dans un nœud AnimationPlayer.

Comme vous utilisez rarement des scènes importées directement dans Godot (elles sont soit instanciées soit héritées), vous pouvez placer le nœud AnimationTree dans votre nouvelle scène qui contient celle importée. Ensuite, pointez le nœud AnimationTree vers l' AnimationPlayer qui a été créé dans la scène importée.

C'est comme ça que ça se passe dans la démo Third Person Shooter, pour référence :

../../_images/animtree1.png

A new scene was created for the player with a CharacterBody3D as root. Inside this scene, the original .dae (Collada) file was instantiated and an AnimationTree node was created.

Création d'une arborescence

Il y a trois principaux types de nœuds qui peuvent être utilisés dans AnimationTree :

  1. Animation nodes, which reference an animation from the linked AnimationPlayer.

  2. Les nœuds racine d'animation, qui sont utilisés pour mélanger les sous-nœuds.

  3. Les nœuds Animation Blend, qui sont utilisés dans AnimationNodeBlendTree comme un seul graphique de mélange via plusieurs ports d'entrée.

Pour définir un nœud racine dans AnimationTree, quelques types sont disponibles :

../../_images/animtree2.png
  • AnimationNodeAnimation : Sélectionne une animation dans la liste et la joue. C'est le nœud racine le plus simple, et généralement pas utilisé directement comme racine.

  • AnimationNodeBlendTree : Contient de nombreux nœuds de type blend, tels que mix, blend2, blend3, one shot, etc. C'est l'une des racines les plus utilisées.

  • AnimationNodeStateMachine : Contient plusieurs nœuds racine en tant qu'enfants dans un graphe. Chaque nœud est utilisé comme un état, et fournit de multiples fonctions pour alterner entre les états.

  • AnimationNodeBlendSpace2D : Permet de placer les nœuds racine dans un espace de mélange 2D. Contrôlez la position du mélange en 2D pour mélanger entre plusieurs animations.

  • AnimationNodeBlendSpace1D : Version simplifiée de ce qui précède (1D).

Arbre de mélange

Un AnimationNodeBlendTree peut contenir à la fois des nœuds racine et des nœuds réguliers utilisés pour le mélange. Les nœuds sont ajoutés au graphique à partir d'un menu :

../../_images/animtree3.webp

Tous les arbres de mélange contiennent un nœud Output par défaut, et quelque chose doit y être connecté pour que les animations puissent être jouées.

La manière la plus simple de tester cette fonctionnalité est de lui connecter un nœud Animation directement :

../../_images/animtree4.png

Cela permettra simplement de lire l'animation. Assurez-vous que l' AnimationTree est actif pour que quelque chose se produise réellement.

Voici une brève description des nœuds disponibles :

Blend2 / Blend3

Ces nœuds se mélangent entre deux ou trois entrées par une valeur de mélange spécifiée par l'utilisateur :

../../_images/animtree5.gif

Pour des mélanges plus complexes, il est conseillé d'utiliser des espaces de mélange à la place.

Le mélange peut également utiliser des filtres, c'est-à-dire que vous pouvez contrôler individuellement les pistes qui passent par la fonction de mélange. Ceci est très utile pour superposer des animations les unes sur les autres.

../../_images/animtree6.png

OneShot

Ce nœud exécutera une sous-animation et retourne une fois qu'elle sera terminée. Les temps de mélange pour l'entrée et la sortie peuvent être personnalisés, ainsi que les filtres.

../../_images/animtree6b.gif

After setting the request and changing the animation playback, the one-shot node automatically clears the request on the next process frame by setting its request value to AnimationNodeOneShot.ONE_SHOT_REQUEST_NONE.

# Play child animation connected to "shot" port.
animation_tree.set("parameters/OneShot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)
# Alternative syntax (same result as above).
animation_tree["parameters/OneShot/request"] = AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE

# Abort child animation connected to "shot" port.
animation_tree.set("parameters/OneShot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT)
# Alternative syntax (same result as above).
animation_tree["parameters/OneShot/request"] = AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT

# Get current state (read-only).
animation_tree.get("parameters/OneShot/active"))
# Alternative syntax (same result as above).
animation_tree["parameters/OneShot/active"]

TimeSeek

Ce nœud peut être utilisé pour provoquer une commande de recherche sur n'importe quel sous-enfant du graphe d'animation. Utilisez ce type de nœud pour lire une Animation depuis le début ou depuis une certaine position de lecture à l'intérieur de l'AnimationNodeBlendTree.

After setting the time and changing the animation playback, the seek node automatically goes into sleep mode on the next process frame by setting its seek_request value to -1.0.

# Play child animation from the start.
animation_tree.set("parameters/TimeSeek/seek_request", 0.0)
# Alternative syntax (same result as above).
animation_tree["parameters/TimeSeek/seek_request"] = 0.0

# Play child animation from 12 second timestamp.
animation_tree.set("parameters/TimeSeek/seek_request", 12.0)
# Alternative syntax (same result as above).
animation_tree["parameters/TimeSeek/seek_request"] = 12.0

TimeScale

Allows scaling the speed of the animation (or reverse it) connected to the in input via the scale parameter. Setting the scale to 0 will pause the animation.

Transition

Very simple state machine (when you don't want to cope with a StateMachine node). Animations can be connected to the outputs and transition times can be specified. After setting the request and changing the animation playback, the transition node automatically clears the request on the next process frame by setting its transition_request value to an empty string ("").

# Play child animation connected to "state_2" port.
animation_tree.set("parameters/Transition/transition_request", "state_2")
# Alternative syntax (same result as above).
animation_tree["parameters/Transition/transition_request"] = "state_2"

# Get current state name (read-only).
animation_tree.get("parameters/Transition/current_state")
# Alternative syntax (same result as above).
animation_tree["parameters/Transition/current_state"]

# Get current state index (read-only).
animation_tree.get("parameters/Transition/current_index"))
# Alternative syntax (same result as above).
animation_tree["parameters/Transition/current_index"]

BlendSpace2D

BlendSpace2D est un nœud pour faire des mélanges avancés en deux dimensions. Les points sont ajoutés à un espace bidimensionnel, puis une position peut être contrôlée pour déterminer le mélange :

../../_images/animtree7.gif

The ranges in X and Y can be controlled (and labeled for convenience). By default, points can be placed anywhere (right-click on the coordinate system or use the add point button) and triangles will be generated automatically using Delaunay.

../../_images/animtree8.gif

Il est également possible de dessiner les triangles manuellement en désactivant l'option triangle automatique, bien que cela soit rarement nécessaire :

../../_images/animtree9.png

Enfin, il est possible de changer le mode de mélange. Par défaut, le mélange se fait par interpolation des points à l'intérieur du triangle le plus proche. Lorsque vous traitez des animations 2D (image par image), vous pouvez vouloir passer en mode Discret. Si vous souhaitez conserver la position de lecture actuelle lorsque vous passez d'une animation discrète à une autre, il existe un mode Carry. Ce mode peut être modifié dans le menu Blend :

../../_images/animtree10.png

BlendSpace1D

Ceci est similaire aux espaces de fusion 2D, mais en une seule dimension (donc les triangles ne sont pas nécessaires).

Machine à état

This node acts as a state machine with root nodes as states. Root nodes can be created and connected via lines. States are connected via Transitions, which are connections with special properties. Transitions are uni-directional, but two can be used to connect in both directions.

../../_images/animtree11.gif

There are many types of transition:

../../_images/animtree12.png
  • Immediate : Passera immédiatement à l'état suivant. L'état actuel se terminera et se fondra dans le début du nouveau.

  • Sync : Passera immédiatement à l'état suivant, mais cherchera le nouvel état à la position de lecture de l'ancien état.

  • At End : Attendra la fin de la lecture de l'état actuel, puis passera au début de l'animation de l'état suivant.

Les transitions ont également quelques propriétés. Cliquez sur n'importe quelle transition et elle sera affichée dans le dock de l'inspecteur :

../../_images/animtree13.png
  • Switch Mode est le type de transition (voir ci-dessus), il peut être modifié après la création ici.

  • Auto Advance activera automatiquement la transition lorsque cet état sera atteint. Cela fonctionne mieux avec le mode de commutation At End.

  • Advance Condition activera l'avance automatique lorsque cette condition est définie. Il s'agit d'une zone de texte personnalisée qui peut être remplie avec un nom de variable. La variable peut être modifiée à partir du code (nous y reviendrons plus tard).

  • Xfade Time est le temps de fondu enchaîné entre cet état et le suivant.

  • Priority is used together with the travel() function from code (more on this later). Lower priority transitions are preferred when travelling through the tree.

  • Disabled toggles disabling this transition (when disabled, it will not be used during travel or auto advance).

For better blending

In Godot 4.0+, in order for the blending results to be deterministic (reproducible and always consistent), the blended property values must have a specific initial value. For example, in the case of two animations to be blended, if one animation has a property track and the other does not, the blended animation is calculated as if the latter animation had a property track with the initial value.

When using Position/Rotation/Scale 3D tracks for Skeleton3D bones, the initial value is Bone Rest. For other properties, the initial value is 0 and if the track is present in the RESET animation, the value of its first keyframe is used instead.

For example, the following AnimationPlayer has two animations, but one of them lacks a Property track for Position.

../../_images/blending1.webp

This means that the animation lacking that will treat those Positions as Vector2(0, 0).

../../_images/blending2.webp

This problem can be solved by adding a Property track for Position as an initial value to the RESET animation.

../../_images/blending3.webp ../../_images/blending4.webp

Note

Be aware that the RESET animation exists to define the default pose when loading an object originally. It is assumed to have only one frame and is not expected to be played back using the timeline.

Also keep in mind that the Rotation 3D tracks and the Property tracks for 2D rotation with Interpolation Type set to Linear Angle or Cubic Angle will prevent rotation of more than 180 degrees from the initial value as blended animation.

This can be useful for Skeleton3Ds to prevent the bones penetrating the body when blending animations. Therefore, Skeleton3D's Bone Rest values should be as close to the midpoint of the movable range as possible. This means that for humanoid models, it is preferable to import them in a T-pose.

../../_images/blending5.webp

You can see that the shortest rotation path from Bone Rests is prioritized rather than the shortest rotation path between animations.

If you need to rotate Skeleton3D itself more than 180 degrees by blend animations for movement, you can use Root Motion.

Racine de mouvement

Lorsque vous travaillez avec des animations 3D, une technique populaire consiste pour les animateurs à utiliser l'os du squelette racine pour donner du mouvement au reste du squelette. Cela permet d'animer des personnages d'une manière où les pas correspondent réellement au sol en-dessous. Il permet également une interaction précise avec les objets lors des cinématiques.

Lors de la lecture de l'animation dans Godot, il est possible de sélectionner cet os comme piste de mouvement racine. Ce faisant, la transformation de l'os sera annulée visuellement (l'animation restera en place).

../../_images/animtree14.png

Ensuite, le mouvement réel peut être récupéré via l'API AnimationTree comme une transformation :

# Get the motion delta.
animation_tree.get_root_motion_position()
animation_tree.get_root_motion_rotation()
animation_tree.get_root_motion_scale()

# Get the actual blended value of the animation.
animation_tree.get_root_motion_position_accumulator()
animation_tree.get_root_motion_rotation_accumulator()
animation_tree.get_root_motion_scale_accumulator()

This can be fed to functions such as CharacterBody3D.move_and_slide to control the character movement.

There is also a tool node, RootMotionView, that can be placed in a scene and will act as a custom floor for your character and animations (this node is disabled by default during the game).

../../_images/animtree15.gif

Contrôle depuis le code

Après avoir construit l'arbre et l'avoir prévisualisé, la seule question qui reste est "Comment tout cela est-il contrôlé depuis le code ?".

Keep in mind that the animation nodes are just resources and, as such, they are shared between all instances using them. Setting values in the nodes directly will affect all instances of the scene that uses this AnimationTree. This is generally undesirable, but does have some cool use cases, e.g. you can copy and paste parts of your animation tree, or reuse nodes with a complex layout (such as a state machine or blend space) in different animation trees.

Les données d'animation actuelles sont contenues dans le nœud AnimationTree et sont accessibles via les propriétés. Consultez la section "Paramètres" du nœud AnimationTree pour voir tous les paramètres qui peuvent être modifiés en temps réel :

../../_images/animtree16.png

Ceci est pratique car il permet de les animer à partir d'un AnimationPlayer, ou même de l' AnimationTree lui-même, permettant la réalisation d'une logique d'animation très complexe.

Pour modifier ces valeurs à partir du code, il faut obtenir le chemin de la propriété. Cela se fait facilement en passant la souris sur l'un des paramètres :

../../_images/animtree17.png

Ce qui permet de les régler ou de les lire :

animation_tree.set("parameters/eye_blend/blend_amount", 1.0)
# Simpler alternative form:
animation_tree["parameters/eye_blend/blend_amount"] = 1.0

Voyage de la machine à état

One of the nice features in Godot's StateMachine implementation is the ability to travel. The graph can be instructed to go from the current state to another one, while visiting all the intermediate ones. This is done via the A* algorithm. If there is no path of transitions starting at the current state and finishing at the destination state, the graph teleports to the destination state.

Pour utiliser la capacité de déplacement, vous devez d'abord récupérer l'objet AnimationNodeStateMachinePlayback du nœud AnimationTree (il est exporté comme une propriété).

var state_machine = animation_tree["parameters/playback"]

Une fois récupéré, il peut être utilisé en appelant l'une des nombreuses fonctions qu'il offre :

state_machine.travel("SomeState")

La machine à états doit être en cours d'exécution avant que vous puissiez voyager. Assurez-vous d'appeler start() ou de choisir un nœud pour Jouer automatiquement au chargement.

../../_images/animtree18.png