Up to date

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

Usando 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 sub-animació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

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.

Creando un árbol

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

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

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

Arbol de mezcla

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.webp

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

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

Este nodo puede usarse para hacer que un comando de búsqueda suceda a cualquier sub-hijo del gráfico de animación. Utilice este tipo de nodo para reproducir una Animación desde el inicio o una determinada posición de reproducción dentro del 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.

Transición

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

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

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() desde el 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).

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

Nota

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.

Movimiento raíz

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:

# 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.

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:

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

Viaje de la máquina de estados

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.

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

var state_machine = animation_tree["parameters/playback"]

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

state_machine.travel("SomeState")

La máquina de estado debe estar funcionando antes de que pueda viajar. Asegúrese de llamar a start() o elegir un nodo para Autoreproducir al cargar.

../../_images/animtree18.png