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, bézier, appel de fonction, audio et 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.

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

Une nouvelle scène a été créée pour le joueur avec un KinematicBody comme racine. Dans cette scène, le fichier original .dae (Collada) a été instancié et un nœud AnimationTree a été créé.

Création d'une arborescence

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

  1. Les nœuds d'animation, qui référencent une animation de l' AnimationTree lié.
  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.png

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

Seek

Ce nœud peut être utilisé pour faire en sorte qu'une commande de recherche soit exécutée sur n'importe quel sous-enfant du graphe. Après avoir réglé le temps, cette valeur revient à -1.

TimeScale

Permet de mettre à l'échelle la vitesse de l'animation (ou de l'inverser) dans n'importe quel nœud enfant. En le mettant à 0, l'animation sera mise en pause.

Transition

Machine à états très simple (quand vous ne voulez pas gérer un nœud StateMachine). Des animations peuvent être connectées aux sorties et des temps de transition peuvent être spécifiés.

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

Les plages en X et Y peuvent être contrôlées (et étiquetées pour plus de commodité). Par défaut, les points peuvent être placés n'importe où (il suffit de faire un clic droit sur le système de coordonnées ou d'utiliser le bouton ajouter un point) et les triangles seront générés automatiquement à l'aide de 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

Ce nœud est une machine à états relativement simple. 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.

../../_images/animtree11.gif

Il existe de nombreux types de transitions :

../../_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 est utilisé avec la fonction travel() depuis le code (plus d'informations plus tard). Lors du voyage d'un état à un autre, donne plus de priorité à ce nœud.
  • Désactivé permet de désactiver cette transition (elle ne sera pas utilisée pendant le voyage ou l'avance automatique).

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 :

anim_tree.get_root_motion_transform()
animTree.GetRootMotionTransform();

Ceci peut être fourni à des fonctions telles que KinematicBody.move_and_slide pour contrôler le mouvement des personnages.

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é pendant le jeu).

../../_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 ?".

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 cette AnimationTree. Ceci 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 une machine à états ou un espace de fusion) 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 :

../../_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 :

anim_tree.set("parameters/eye_blend/blend_amount", 1.0)
# Simpler alternative form:
anim_tree["parameters/eye_blend/blend_amount"] = 1.0
animTree.Set("parameters/eye_blend/blend_amount", 1.0);

Voyage de la machine à état

Une des caractéristiques intéressantes de l'implémentation de la StateMachine de Godot est la possibilité de voyager. On peut demander au graphique de passer de l'état actuel à un autre, en visitant tous les états intermédiaires. C'est fait via l'algorithme A*.

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 = anim_tree["parameters/StateMachine/playback"]
AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)animTree.Get("parameters/StateMachine/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")