Using AnimationTree

Introducción

Con AnimationPlayer, Godot tiene uno de los sistemas de animación más flexibles que puedas encontrar en cualquier motor de juegos. La capacidad de animar prácticamente cualquier propiedad en cualquier nodo o recurso, además de tener pistas dedicadas de transformación, Bézier, llamada de funciones, audio y pistas de subanimación, es prácticamente única.

Sin embargo, el soporte para mezclar esas animaciones a través de AnimationPlayer es relativamente limitado, ya que sólo se puede establecer un tiempo fijo de transición de cruce.

AnimationTree es un nuevo nodo introducido en Godot 3.1 para gestionar transiciones avanzadas. Sustituye al antiguo AnimationTreePlayer, mientras que añade una gran cantidad de características y flexibilidad.

Creando un AnimationTree

Antes de empezar, debe quedar claro que un nodo AnimationTree no contiene sus propias animaciones. En su lugar, utiliza las animaciones contenidas en un nodo AnimationPlayer. De esta manera, puedes editar tus animaciones (o importarlas desde una escena 3D) como de costumbre y luego usar este nodo extra para controlar la reproducción.

La forma más común de usar "AnimationTree" es en una escena 3D. Al importar tus escenas de un formato de intercambio 3D, normalmente vendrán con animaciones integradas ( ya sean múltiples o separadas desde una más grande en la importación). Al final, la escena importada de Godot contendrá las animaciones en un nodo AnimationPlayer.

Como en raras ocasiones se utilizan las escenas importadas directamente en Godot (son instanciadas o heredadas), puedes colocar el nodo AnimationTree en tu nueva escena que contiene lo importado. Después, apunta el nodo AnimationTree al AnimationPlayer que fue creado en la escena importada.

Así es como se hace en Third Person Shooter demo, como referencia:

../../_images/animtree1.png

Se creó una nueva escena para el jugador con un KinematicBody como raíz. Dentro de esta escena, el archivo original .dae (Collada) fue instanciado y se creó un nodo AnimationTree.

Creando un árbol

Hay tres tipos principales de nodos que pueden ser usados en AnimationTree:

  1. Nodos Animation, que hacen referencia a una animación del AnimationTree vinculado.

  2. Nodos Animation Root, que se utilizan para combinar subnodos.

  3. Nodos Animation Blend, que se utilizan dentro de AnimationNodeBlendTree para combinar un solo gráfico a través de múltiples puertos de entrada.

Para establecer un nodo raíz en AnimationTree, hay algunos tipos disponibles:

../../_images/animtree2.png
  • AnimationNodeAnimation: Selecciona una animación de la lista y la reproduce. Este es el nodo raíz más simple, y generalmente no se usa directamente como raíz.

  • AnimationNodeBlendTree: Contiene muchos nodos de tipo blend, como mix, blend2, blend3, one shot, etc. Esta es una de las raíces más utilizadas.

  • AnimationNodeStateMachine: Contiene múltiples nodos raíz como hijos en un gráfico. Cada nodo se utiliza como un estado, y proporciona múltiples funciones para alternar entre los estados.

  • AnimationNodeBlendSpace2D: Permite colocar nodos raíz en un espacio de mezcla 2D. Controla la posición de mezcla en 2D para combinar varias animaciones.

  • AnimationNodeBlendSpace1D: Versión simplificada del anterior (1D).

Blend tree

Un AnimationNodeBlendTree puede contener nodos raíz y comunes usados para la mezcla. Los nodos se añaden al gráfico desde un menú:

../../_images/animtree3.png

Todos los blend trees contienen un nodo Output por defecto, y algo tiene que estar conectado a él para que las animaciones puedan reproducirse.

La forma más fácil de probar esta funcionalidad es conectar un nodo de Animation directamente:

../../_images/animtree4.png

Esto simplemente reproducirá la animación. Asegúrate de que el AnimationTree esté activo para que algo suceda en verdad.

A continuación se presenta una breve descripción de los nodos disponibles:

Blend2 / Blend3

Estos nodos se mezclarán entre dos o tres entradas mediante un valor de mezcla especificado por el usuario:

../../_images/animtree5.gif

Para mezclas más complejas, se aconseja usar espacios de mezcla en su lugar.

La mezcla también puede utilizar filtros, es decir, se puede controlar individualmente cuáles son las pistas que pasan por la función de mezcla. Esto es muy útil para superponer animaciones.

../../_images/animtree6.png

OneShot

Este nodo ejecutará una subanimación y volverá una vez que termine. Los tiempos de mezcla para el desvanecimiento de entrada y salida pueden ser personalizados, así como los filtros.

../../_images/animtree6b.gif

Seek

This node can be used to cause a seek command to happen to any sub-children of the animation graph. Use this node type to play an Animation from the start or a certain playback position inside the 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_position value to -1.0.

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

# Play child animation from 12 second timestamp.
anim_tree.set("parameters/Seek/seek_position", 12.0)
# Alternative syntax (same result as above).
anim_tree["parameters/Seek/seek_position"] = 12.0
// Play child animation from the start.
animTree.Set("parameters/Seek/seek_position", 0.0);

// Play child animation from 12 second timestamp.
animTree.Set("parameters/Seek/seek_position", 12.0);

TimeScale

Permite escalar la velocidad de la animación (o invertirla) en cualquier nodo hijo. Poniéndolo en 0 se detendrá la animación.

Transition

Una máquina de estados muy simple (cuando no quieres lidiar con un nodo StateMachine). Las animaciones pueden ser conectadas a las salidas y se pueden especificar los tiempos de transición.

BlendSpace2D

BlendSpace2D es un nodo para hacer mezclas avanzadas en dos dimensiones. Se añaden puntos a un espacio bidimensional y luego se puede controlar una posición para determinar la mezcla:

../../_images/animtree7.gif

Los rangos en X e Y pueden ser controlados (y etiquetados para mayor comodidad). Por defecto, los puntos pueden ser colocados en cualquier lugar (sólo hay que hacer clic con el botón derecho del ratón en el sistema de coordenadas o usar el botón añadir punto) y los triángulos se generarán automáticamente usando Delaunay.

../../_images/animtree8.gif

También es posible dibujar los triángulos manualmente desactivando la opción triángulo automático, aunque esto rara vez es necesario:

../../_images/animtree9.png

Finalmente, es posible cambiar el modo de mezcla. Por defecto, la mezcla se realiza interpolando puntos dentro del triángulo más cercano. Cuando se trata de animaciones 2D (cuadro por cuadro), es posible que quieras cambiar al modo Discrete. Por otra parte, si quieres mantener la posición actual de reproducción al cambiar entre las animaciones discretas, hay un modo Carry. Este modo puede cambiarse en el menú Blend:

../../_images/animtree10.png

BlendSpace1D

Esto es similar a los espacios de mezcla 2D, pero en una dimensión (por lo que los triángulos no son necesarios).

StateMachine

Este nodo es una máquina de estado relativamente simple. Los nodos raíz pueden ser creados y conectados a través de líneas. Los estados se conectan a través de Transiciones, que son conexiones con propiedades especiales. Las transiciones son unidireccionales, pero dos se pueden usar para conectarlos en ambos sentidos.

../../_images/animtree11.gif

Existen varios tipos de transición:

../../_images/animtree12.png
  • Inmediato: Cambiará al siguiente estado inmediatamente. El estado actual terminará y se mezclará con el principio del nuevo.

  • Sync: Cambiará al siguiente estado inmediatamente, pero buscará el nuevo estado a la posición de reproducción del viejo estado.

  • Al final: Esperará a que termine la reproducción del estado actual, y luego pasará al principio de la animación del siguiente estado.

Las transiciones también tienen algunas propiedades. Haga clic en cualquier transición y se mostrará en el muelle de inspección:

../../_images/animtree13.png
  • Switch Mode es el tipo de transición (ver arriba), puede ser modificado después de la creación aquí.

  • Auto Avance encenderá la transición automáticamente cuando se alcance este estado. Esto funciona mejor con el modo de interruptor Al final.

  • Condición de avance activará el avance automático cuando se establezca esta condición. Este es un campo de texto personalizado que puede ser llenado con un nombre de variable. La variable puede ser modificada desde el código (más sobre esto más adelante).

  • Xfade Time es el tiempo para cruzar entre este estado y el siguiente.

  • Prioridad se usa junto con la función travel() del código (más sobre esto más adelante). Cuando se viaja de un estado a otro, hay que dar más prioridad a este nodo.

  • Desactivado permite desactivar esta transición (no se usará durante el viaje o el avance automático).

Root motion

Cuando se trabaja con animaciones 3D, una técnica popular es que los animadores usen el hueso del esqueleto de la raíz para dar movimiento al resto del esqueleto. Esto permite animar los personajes de manera que los pasos coincidan con el piso de abajo. También permite una interacción precisa con los objetos durante la cinematografía.

Al reproducir la animación en Godot, es posible seleccionar este hueso como la pista de movimiento de raíz. Al hacerlo, se cancelará la transformación del hueso visualmente (la animación se mantendrá en su lugar).

../../_images/animtree14.png

Después, el movimiento real puede ser recuperado a través de la API AnimationTree como una transformación:

anim_tree.get_root_motion_transform()
animTree.GetRootMotionTransform();

Esto puede ser alimentado a funciones como KinematicBody.move_and_slide para controlar el movimiento del personaje.

También hay un nodo de herramientas, RootMotionView, que puede ser colocado en una escena y actuará como un piso personalizado para tu personaje y las animaciones (este nodo normalmente se desactiva durante el juego).

../../_images/animtree15.gif

Controlando desde código

Después de construir el árbol y previsualizarlo, la única pregunta que queda es "¿Cómo se controla todo esto desde el código?".

Tengan en cuenta que los nodos de animación son sólo recursos y, como tales, se comparten entre todas las instancias. Poner valores en los nodos afectará directamente a todas las instancias de la escena que usa este AnimationTree. Sin embargo, esto tiene algunos casos de uso interesantes, por ejemplo, puedes copiar y pegar partes de tu árbol de animación, o reutilizar nodos con un diseño complejo (como una máquina de estados o un espacio de mezcla) en diferentes árboles de animación.

Los datos de la animación real están contenidos en el nodo AnimationTree y se accede a ellos a través de las propiedades. Revisa la sección "Parameters" del nodo AnimationTree para ver todos los parámetros que pueden ser modificados en tiempo real:

../../_images/animtree16.png

Esto es útil porque permite animarlos desde un AnimationPlayer, o incluso desde el mismo AnimationTree, permitiendo la realización de una lógica de animación muy compleja.

Para modificar estos valores del código, se debe obtener el camino de la propiedad. Esto se hace fácilmente pasando el ratón por encima de cualquiera de los parámetros:

../../_images/animtree17.png

Lo que permite establecerlos o leerlos:

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

Viaje de la máquina de estados

Una de las características agradables de la implementación de la Máquina de Estados de Godot es la capacidad de viajar. El gráfico puede ser instruido para ir del estado actual a otro, mientras se visitan todos los intermedios. Esto se hace a través del algoritmo A* (Algoritmo Estrella).

Para usar la habilidad de viajar, primero debes recuperar el objeto AnimationNodeStateMachinePlayback del nodo AnimationTree (se exporta como una propiedad).

var state_machine = anim_tree["parameters/playback"]
AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)animTree.Get("parameters/playback");

Una vez recuperado, se puede utilizar llamando a una de las muchas funciones que ofrece:

state_machine.travel("SomeState")
stateMachine.Travel("SomeState")

The state machine must be running before you can travel. Make sure to either call start() or choose a node to Autoplay on Load.

../../_images/animtree18.png