AnimationNodeAnimation in Godot – Complete Guide

Welcome to our comprehensive tutorial on the AnimationNodeAnimation class in Godot 4. If you’ve ever wanted to breathe life into your game characters and objects with smooth, dynamic animations, diving into Godot’s animation system is a must. Through this class, you can choreograph movement, transformation, and more to create engaging and immersive gameplay experiences. As we guide you through the ins and outs of the AnimationNodeAnimation, you’ll discover just how easy and powerful animating in Godot can be—no matter where you are in your coding journey.

What is AnimationNodeAnimation?

The AnimationNodeAnimation class is an essential component within Godot’s advanced animation system. It acts as an input animation for an AnimationNodeBlendTree, allowing you to add various animations as resources.

What is an AnimationNodeBlendTree?

An AnimationNodeBlendTree works as a workspace where multiple animation nodes, like the AnimationNodeAnimation, come together to blend animations and create complex sequences.

Why Should I Learn It?

By mastering the AnimationNodeAnimation class, you’ll unlock the potential to intricately control and sequence animations, elevating your game’s visual storytelling. Whether you’re a beginner eager to learn the basics or an experienced developer looking to refine your craft, understanding this class is a step towards building more interactive and responsive games.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Let’s dive into the practical aspects of using the AnimationNodeAnimation class in Godot 4. We’ll start by creating a simple animation in Godot and then loading it into an AnimationNodeAnimation. From there, we’ll proceed to more advanced examples, manipulating animations to work fluidly within our game environment.

Creating a Simple Animation

Before we can use the AnimationNodeAnimation, we need to create an animation in Godot’s AnimationPlayer. Let’s say we want to create a “jump” animation for a character.

var animation_player = AnimationPlayer.new()
var animation = Animation.new()

# Set up the animation (1 second long for example)
animation.length = 1.0
animation.loop = true

# Add a track and keys for the property to be animated (e.g., the position of a sprite)
animation.track_insert_key(0, 0.0, Vector2(100, 100)) # start position
animation.track_insert_key(0, 0.5, Vector2(100, 50))  # top of the jump
animation.track_insert_key(0, 1.0, Vector2(100, 100)) # end position, same as start

# Add the animation to the AnimationPlayer
animation_player.add_animation("jump", animation)

Loading an Animation into AnimationNodeAnimation

Once we’ve created an animation, we can load it into an AnimationNodeAnimation node that’s part of an AnimationTree as follows:

var animation_tree = AnimationTree.new()
var animation_node = AnimationNodeAnimation.new()

# Assign the AnimationPlayer to the AnimationTree
animation_tree.anim_player = animation_player

# Load the "jump" animation we created earlier into the AnimationNodeAnimation
animation_node.set_animation("jump")

# Add our AnimationNodeAnimation to the AnimationTree's root blend tree
var root = animation_tree.get("parameters/playback")
root.add_node("JumpAnimation", animation_node)

Blending Animations

Now, let’s blend our “jump” animation with a “walk” animation to create a smooth transition between the two actions.

var blend_node = AnimationNodeBlend2.new()
blend_node.add_input("Jump")
blend_node.add_input("Walk")

root.add_node("Blend", blend_node)
root.connect("JumpAnimation", "Blend", 0)
root.connect("WalkAnimation", "Blend", 1)

# To blend the animations, adjust the blend amount where 0.0 is full "Jump" and 1.0 is full "Walk".
animation_tree.set("parameters/Blend/blend_amount", 0.5)

Controlling the Blend Amount via Code

We might want to control the blend amount programmatically based on player input or game logic. Below is an example of how we could tie the blend amount to a character’s speed.

func _process(delta):
    var speed = get_character_speed()  # Function to get the character's speed
    var blend_amount = clamp(speed / max_speed, 0.0, 1.0)  # Normalize the speed
    animation_tree.set("parameters/Blend/blend_amount", blend_amount)

This basic foundation allows for robust animation management within the Godot Engine, ensuring that your characters and objects interact seamlessly with your game world. As we continue, we’ll explore more advanced functionality and additional tips for fine-tuning your animations to perfection. Stay tuned for more examples in the next part of the tutorial!Let’s further develop our animation blending and handling for more advanced scenarios. Our next step involves adding conditional logic to control animations and using signals to synchronize actions in the game.

Conditional Logic for Animation Transitions

We might want animations to transition only when certain conditions are met, such as the character touching the ground or an ability being off cooldown. Here’s how we can implement such conditions:

func _process(delta):
    if is_on_floor() and Input.is_action_just_pressed("jump"):
        animation_tree.set("parameters/Blend/blend_amount", 0.0)  # Play "Jump" animation.
    elif not is_on_floor():
        animation_tree.set("parameters/Blend/blend_amount", 0.0) # Continue "Jump" animation.
    else:
        animation_tree.set("parameters/Blend/blend_amount", 1.0) # Default to "Walk" animation.

Using Signals to Synchronize Animation with Actions

Animations often need to be synced with game events. Using Godot’s signal system can help achieve smooth synchronization, like triggering a sound effect at the point of a sword swing.

# Connect the signal in your character setup
animation_player.connect("animation_started", self, "_on_Animation_started")

func _on_Animation_started(anim_name):
    if anim_name == "sword_swing":
        # Play sound at the beginning of the sword swing animation
        sword_swing_sound.play()

Implementing Animation Callbacks

Sometimes, we want certain things to happen when an animation ends, like triggering the next action in a combo chain. Callbacks can be added to do just that.

animation_player.connect("animation_finished", self, "_on_Animation_finished")

func _on_Animation_finished(anim_name):
    if anim_name == "strike":
        # Prepare the next move or reset the combo
        handle_combo_transition()

Adjusting Animation Speed

Controlling the speed of an animation is another way to dynamically modify your character’s behavior, making it respond to in-game context, like moving slower when injured.

func set_animation_speed(speed_scale):
    animation_tree.set("parameters/Blend/blend_speed", speed_scale)

Now let’s consider an example where our character’s speed needs to change based on the level of a “slow down” debuff.

func _process(delta):
    var debuff_strength = get_debuff_strength()
    var speed_scale = max(0.1, 1.0 - debuff_strength) # Ensure speed doesn't go below 10%
    set_animation_speed(speed_scale)

Applying Animation-Driven Movement

For added realism, you can use root motion or animation-driven movement, where the animation itself can move the character while maintaining synchrony with the player’s input.

# Here's an example of how you could set this up:
animation_tree.set("parameters/Blend/use_animation_translation", true)

You would then need to make sure your character’s movement code is set to handle this appropriately, blending manual movement control with animation-based motion.

func _physics_process(delta):
    var input_vector = Vector2(0, 0)
    input_vector.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
    input_vector.y = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
    input_vector = input_vector.normalized()

    # If we're using animation-driven movement, apply root motion
    if animation_tree.get("parameters/Blend/use_animation_translation"):
        apply_animation_translation(delta)

    # Otherwise, use the input vector for direct control
    else:
        move_and_slide(input_vector * move_speed)

These examples showcase the versatility of Godot’s animation system and particularly the power of the AnimationNodeAnimation class. By utilizing these methods, you can create more nuanced and professional animations in your games, reacting dynamically to game states and player inputs for a truly immersive experience.Imagine you’re designing a character who can transition from a walk to a sprint animation based on the player’s input. We’ll need to manage blending between these states, and also incorporate a sprinting mechanic that uses stamina.

Blending Walk and Sprint Animations

First, we set up a blend node specifically for our walk and sprint animations.

var walk_sprint_blend = AnimationNodeBlend2.new()
walk_sprint_blend.add_input("Walk")
walk_sprint_blend.add_input("Sprint")

root.add_node("WalkSprintBlend", walk_sprint_blend)
root.connect("WalkAnimation", "WalkSprintBlend", 0)
root.connect("SprintAnimation", "WalkSprintBlend", 1)

We can then dynamically adjust the blend based on the player’s input, such as holding down a ‘sprint’ key.

func _physics_process(delta):
    var is_sprinting = Input.is_action_pressed("sprint") and has_stamina()
    animation_tree.set("parameters/WalkSprintBlend/blend_amount", is_sprinting ? 1.0 : 0.0)

Implementing Stamina for Sprinting

Next, let’s use a bit of code to add a stamina decrease when sprinting. We’ll need a few variables to keep track of the character’s stamina level.

var stamina = 100.0
var max_stamina = 100.0
var stamina_depletion_rate = 10.0
var stamina_recovery_rate = 5.0

We want to deplete stamina over time while sprinting and recover it otherwise.

func _physics_process(delta):
    var is_sprinting = Input.is_action_pressed("sprint") and has_stamina()
    if is_sprinting:
        stamina = max(0.0, stamina - stamina_depletion_rate * delta)
    else:
        stamina = min(max_stamina, stamina + stamina_recovery_rate * delta)

Our helper function `has_stamina()` can be simple – it just needs to check if the stamina is above a certain threshold.

func has_stamina() -> bool:
    return stamina > 0

Changing Animation Speed According to Stamina

We can also make the sprint animation slow down as stamina decreases, reflecting the player’s exhaustion.

var stamina_threshold_for_speed_reduction = 20.0

func _physics_process(delta):
    var is_sprinting = Input.is_action_pressed("sprint") and has_stamina()
    var blend_amount = is_sprinting ? 1.0 : 0.0
    var sprint_speed_scale = (stamina > stamina_threshold_for_speed_reduction) ? 1.0 : lerp(0.5, 1.0, stamina / stamina_threshold_for_speed_reduction)

    animation_tree.set("parameters/WalkSprintBlend/blend_amount", blend_amount)
    animation_tree.set("parameters/SprintAnimation/animation_speed", sprint_speed_scale)

Reacting to Animation Playback Position

In some cases, we want to execute a function at a specific moment in an animation playback, like when a footstep should make a sound.

# Connect the signal in your character setup
animation_player.connect("animation_changed", self, "_on_Animation_changed")

func _on_Animation_changed(old_name, new_name):
    if new_name == "walk":
        animation_player.current_animation_position = 0.5

At this precise point in the animation, we might want to play a footstep sound.

animation_player.connect("animation_changed", self, "_on_Animation_changed")

func _on_Animation_changed(old_name, new_name, pos):
    if new_name == "walk" and pos == 0.5:
        footstep_sound.play()

Managing Animation Blending for Different Game States

Finally, let’s consider expanding our blend tree for different game states, such as combat or puzzle-solving, where different sets of animations would be required.

var state = "exploration"  # This could also be "combat", "puzzle", etc.

func _physics_process(delta):
    animation_tree.set_active(true)

    match state:
        "exploration":
            handle_exploration_animations(delta)
        "combat":
            handle_combat_animations(delta)
        # Add additional game state handlers as needed.

Each game state handling function would contain its own logic for managing the blend amount and animation parameters within that context.

This concludes our array of examples where we’ve seen how to blend animations, manage character states with stamina, react to specific moments in an animation, and handle different game states within the animation tree. By leveraging these strategies, you can create a smoother and more interactive experience in your Godot 4 projects. Remember, it’s by exploring, iterating, and refining these techniques that you’ll truly bring your game’s animations to life, further enhancing the immersion and responsiveness that players love.

Continuing Your Animation Journey in Godot

As we wrap up this exploration into the AnimationNodeAnimation class in Godot 4, remember that this is just one step in your adventure into game development. Animation is a vibrant and crucial area of game design that brings characters and stories to life. We encourage you to keep building on what you’ve learned, experiment with new ideas, and create animations that capture the imagination of players around the world.

If you’re eager to dive deeper into Godot and broaden your game development skills, our Godot Game Development Mini-Degree is the perfect next step. This comprehensive series of courses covers everything from the basics of using 2D and 3D assets to creating intricate gameplay systems and mechanics. Whether you’re just starting out or looking to add more tools to your repertoire, these project-based courses will provide you with practical knowledge to create your own games using Godot 4.

For a wider array of topics and to explore other facets of game development with this engine, check out our full catalog of Godot courses. With Zenva, you can go from beginner to professional at your own pace, building a robust skillset that opens doors to exciting opportunities in the game development field. Continue crafting your own game worlds, and let your creativity soar with Zenva’s support every step of the way.

Conclusion

As you venture into the realms of game animation with Godot 4, embracing the nuances of the AnimationNodeAnimation class propels your projects forward. We at Zenva are thrilled to have guided you through this journey, and we’re committed to helping you continue expanding your skillset. Remember that each line of code, each animation sequence, and every game mechanic you master contributes to the awe-inspiring universes you’re capable of creating.

Whether you choose to delve further into the intricacies of Godot or expand your expertise across other aspects of game development, our Godot Game Development Mini-Degree stands ready to usher you into your next chapter. Your ambition and creativity, paired with our educational resources, make an unstoppable force. Let’s keep the momentum going – the world eagerly awaits the games only you can dream up.

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.