AnimationStateMachine, all connected to all conditionally with a cross-fade

Godot Version

4.6.2

Question

My Idle node in the AnimationTree currently looks like this:

So, each animation is (conditionally) connected to every other and the controlling code looks like this:

func _apply_animation_conditions(v: WeaponVisuals) -> void:
	animation_tree.set("parameters/Idle/conditions/no_weapon", v.idle_anim_type == WeaponVisuals.IdleAnimType.NONE)
	animation_tree.set("parameters/Idle/conditions/melee", v.idle_anim_type == WeaponVisuals.IdleAnimType.MELEE)
	animation_tree.set("parameters/Idle/conditions/pistol", v.idle_anim_type == WeaponVisuals.IdleAnimType.PISTOL)
	animation_tree.set("parameters/Idle/conditions/rifle", v.idle_anim_type == WeaponVisuals.IdleAnimType.RIFLE)

The problem is that this is not scalable: it has O(n^2) transitions, and each have to be manually set, which can easily lead to silent bugs.

What I tried:

StateMachine cannot be looped onto itself, and you also cannot connect End node to Start, so I came up with this workaround:

“Empty” node is just Start -> End. Animation node looks like this:

How it works: after each animation loop, Animation node transitions to a no-op State Machine (if we are still in the Idle state) and immediately goes back; if we still have the same animation – we play it again, if weapon type has changed – we play another animation.

Cons:

  • only changing animation after the current one ends (setting exit transitions to “Immediate” or “Sync” creates a fast-circling loop)
  • each time an animation ends, we have 1 frame of some “default” state; I’m not sure where this comes from, as I don’t even have a RESET animation, which just looks terrible

Another solution I was thinking about is creating a BlendSpace1D with “current” and “next” animations, transitioning from “current” to the “next” when changing weapons using tweens, then replacing “current” with whatever is in the “next” and changing back to the “current”. I did not implement it, because I really would like to encapsulate animations logic inside AnimationTree, and don’t have to manually swithc it with code (otherwise, why even have an AnimationTree, when I can just manually set animations using AnimationPlayer). Theoretically, though, this would break if I switch weapons while in transitions between animations. I can circumvent it by checking the current state in the “process” function, but by this point it’s like implementing your own AnimationTree.

I also thought about BlendSpace2D, but it is not the correct usage of a BlendSpace (I don’t actually need to blend anything), nor the real solution, as it will break as soon as I have more than 4 different animations (because I will have to transition over other animations, which is undesirable).

So, what I really need: a set of animations, each with its own condition, and with smooth transitioning from any to any without manually “travelling”, just based on the current state. Is it achievable in Godot, or do I really have to control animations with imperative code at this point?

Thank you.

Check out AnimationNodeBlendTree. Make that your AnimationTree tree_root.

Then inside it you can put smaller StateMachines, like my MoveStateMachine.

Thank you for your answer.

I don’t think I fully understand you though. Let’s say I create a state machine for each weapon I have. Inside these machines, it’ll be pretty straightforward. But when I change weapons, how do I transition with cross-fading between different state machines, without having to manually set up a blend node for each pair?

You can programmatically switch them out in code.

Unfortunately, switching animations with code is the one thing I was hoping to avoid. I might have to, though, since I don’t see another solution as well.

Thank you for your time anyway!