Work with nested state machines in AnimationTree

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Yaann

I have a character with multiple weapons all of them having their own animations and put them all inside a AnimationTree Node, instead of going trough the hassle of making a giant and confusing animationtree, without talking about the scripting nightmare it was going to be since it’s mostly the same animation cycles (walk, idle, attack,etc) repeating with only the animations for each weapons changing.
I decided instead to put each weapon animation in its own nested state machine like this:

Each state machine has basically the same animation states (with the animations being different of course):

Now all I want to do is being able to switch between nested state machines depedent of what weapon my character is using. Every help is much appreciated!

:bust_in_silhouette: Reply From: Yaann

Okay, I’ve figured it on my own, it’s pretty long to explain for my end but here’s at least how you switch from the root state machine to a sub-state machine (it’s on C# but it shouldn’t be that hard to convert it to GDScript).

playback = (AnimationNodeStateMachinePlayback) GetNode<AnimationTree>("AnimationTree").Get("parameters/playback");
    playback.Start(sub_machine_state);
    playback = (AnimationNodeStateMachinePlayback) GetNode<AnimationTree>("AnimationTree").Get("parameters/sub_machine_state/playback");
    playback.Start("idle");

However I don’t know if I’m going to keep it like that, there’s plenty of FSM plugins in the Assetlib that probably do the work without the hassle.

1 Like

I hate necroing an old thread but I stumbled upon this when having a similar issue so figured I’d leave a note for people in the future.

Gdscript with Godot version 4.2.1
Animation Tree with BlendSpace2Ds and a StateMachine(attack)
attack has BlendSpace2Ds, one for each weapon type
Screenshots of animation tree below code etc

In my player script I have a match to switch between MOVE state and ATTACK state which are from a local enum

At the top of my player.gd I have this:

@onready var animation_tree:AnimationTree = $PlayerAnimationTree
@onready var animation_state_root:AnimationNodeStateMachinePlayback = $PlayerAnimationTree.get("parameters/playback")
@onready var animation_state_attack:AnimationNodeStateMachinePlayback = $PlayerAnimationTree.get("parameters/attack/playback")

In _physics_process() I have the following for blend space params:

if normalizedVector != Vector2.ZERO:
	animation_tree.set("parameters/idle/blend_position", normalizedVector)
	animation_tree.set("parameters/walk/blend_position", normalizedVector)
	animation_tree.set("parameters/run/blend_position", normalizedVector)
    animation_tree.set('parameters/attack/{weapon}/blend_position'.format({"weapon": player_globals.current_weapon.name}), normalizedVector)

When the player triggers an attack the following code is run:

    # travel to attack(state machine)
	animation_state_root.travel("attack")
    # travel to correct BlendSpace2D inside the nested state machine
	animation_state_attack.travel(player_globals.current_weapon.name)

	player_globals.current_speed = 0.0
	set_velocity(Vector2.ZERO)
    # easy way to wait for attack animation to finish before moving on
	await animation_tree.animation_finished
	state = MOVE

And here are some screenshots for reference: