Up to date
This page is up to date for Godot 4.3.
If you still find outdated information, please open an issue.
Utiliser les AnimationTree
Introduction
Avec AnimationPlayer, Godot possède l'un des systèmes d'animation les plus flexibles que l'on puisse trouver dans un moteur de jeu. La possibilité d'animer à peu près n'importe quelle propriété dans n'importe quel nœud ou ressource, ainsi que d'avoir des pistes dédiées de transformation, de Bézier, d'appel de fonction, d'audio et de sous-animation, est à peu près 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.
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 :
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 :
Animation nodes, which reference an animation from the linked
AnimationPlayer.Les nœuds racine d'animation, qui sont utilisés pour mélanger les sous-nœuds.
Les nœuds Animation Blend, qui sont utilisés dans
AnimationNodeBlendTreecomme 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 :
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 :
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 :
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 :
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.
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.
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"]
// Play child animation connected to "shot" port.
animationTree.Set("parameters/OneShot/request", (int)AnimationNodeOneShot.OneShotRequest.Fire);
// Abort child animation connected to "shot" port.
animationTree.Set("parameters/OneShot/request", (int)AnimationNodeOneShot.OneShotRequest.Abort);
// Get current state (read-only).
animationTree.Get("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
// Play child animation from the start.
animationTree.Set("parameters/TimeSeek/seek_request", 0.0);
// Play child animation from 12 second timestamp.
animationTree.Set("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"]
// Play child animation connected to "state_2" port.
animationTree.Set("parameters/Transition/transition_request", "state_2");
// Get current state name (read-only).
animationTree.Get("parameters/Transition/current_state");
// Get current state index (read-only).
animationTree.Get("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 :
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.
Il est également possible de dessiner les triangles manuellement en désactivant l'option triangle automatique, bien que cela soit rarement nécessaire :
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 :
BlendSpace1D
Ceci est similaire aux espaces de fusion 2D, mais en une seule dimension (donc les triangles ne sont pas nécessaires).
Machine à état
Ce nœud est un automate avec des nœuds racines comme états. Les nœuds racine peuvent être créés et reliés par des lignes. Les états sont connectés via des Transitions, qui sont des connexions avec des propriétés spéciales. Les transitions sont unidirectionnelles, mais deux peuvent être utilisées pour se connecter dans les deux sens.
Il existe de nombreux types de transitions :
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 :
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 est utilisé avec la fonction
travel()depuis le code (plus d'informations plus tard). Les transitions à basse priorité sont préférées lors du parcours de l'arbre.Désactivé permet de désactiver cette transition (lorsqu'elle est désactivée, elle ne sera pas utilisée pendant le parcours ou l'avance automatique).
Pour un meilleur mélange
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.
This means that the animation lacking that will treat those Positions as Vector2(0, 0).
This problem can be solved by adding a Property track for Position as an initial value to the RESET animation.
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.
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).
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()
// Get the motion delta.
animationTree.GetRootMotionPosition();
animationTree.GetRootMotionRotation();
animationTree.GetRootMotionScale();
// Get the actual blended value of the animation.
animationTree.GetRootMotionPositionAccumulator();
animationTree.GetRootMotionRotationAccumulator();
animationTree.GetRootMotionScaleAccumulator();
This can be fed to functions such as CharacterBody3D.move_and_slide to control the character movement.
Il y a aussi un nœud outil, RootMotionView, qui peut être placé dans une scène et qui agira comme un sol personnalisé pour votre personnage et vos animations (ce nœud est normalement désactivé par défaut pendant le jeu).
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 ?".
Gardez à l'esprit que les nœuds d'animation ne sont que des ressources et, en tant que tels, ils sont partagés entre toutes les instances. La définition de valeurs dans les nœuds affectera directement toutes les instances de la scène qui utilise cet AnimationTree. C'est généralement indésirable, mais a quelques cas d'utilisation intéressants, par exemple vous pouvez copier et coller des parties de votre arbre d'animation, ou réutiliser des nœuds avec une disposition complexe (comme un automate ou un espace de mélange) dans différents arbres d'animation.
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 :
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 :
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
animationTree.Set("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"]
AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)animationTree.Get("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")
stateMachine.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.