#How to properly wait for Animation finished in BlendTree/StateMachine?

1 messages · Page 1 of 1 (latest)

soft saffron
#

I have a complex AnimationTree with a Root State Machine.

Start -> Move
Move -> Attack (is_attacking)
Attack -> Move (attack_finished)

"Attack" is a BlendTree that selects the animation depending on the weapon.

Is there a signal that I can connect to when the BlendTree finishes?
The goal is to receive "animation_finished" or the like and set attack_finished to true so the State Machine goes back to Move.

wary reef
#

I assume your Animation Tree Root is a State Machine. State Machine Transitions have a Switch Mode Property. You can set it to "At End" to automatically switch back to the next state.
Make sure you have the Advance Mode set to Auto.

loud marten
#

I'm not sure if it's what you want but you can put this in a "one-shot" node so you wouldn't even have to track it.

#

you just call the blend tree to fire the animation. Have some function calls in the animation for damage or something, and let the blend tree worry about when it finishes and stuff

wary reef
#

Yes. That would be the better approach if the tree root is a blend tree

loud marten
#

even if its not the tree root you can still call this wherever it's at I'm pretty sure. Lemme know if this helps or you need another solution!

soft saffron
#

I need an actual signal. Because I am having my player state machine switch to "attack" which in return sets the "is_attacking" boolean to true.

When the attack animation is supposed to be finished, the player state machine is supposed to be switching back to its previous state.

#

Currently I do this:

public partial class PhysicalAttackState : PlayerState {
    
    private void AnimationTreeOnAnimationFinished(StringName animName) {
        GD.Print(animName);
        switch (animName) {
            // TOOD: await other animations
            case "sword_attack":
                AnimationTree.Set("parameters/conditions/attack_finished",true);
                AnimationTree.Set("parameters/conditions/is_attacking", false);
                EmitSignalRequestStateChange("Move");
                break;
        }
    }

    public override async Task Enter() {
        GD.Print("Fooooooooooo");
        var speed = Player.Combatant.StatProvider.AnimationMultiplier;
        GD.Print("Speed: " + speed);
        AnimationTree.Set("parameters/Attack/attack_speed/scale", speed);
        AnimationTree.Set("parameters/conditions/is_attacking", true);
        AnimationTree.Set("parameters/conditions/attack_finished", false);
        //Connect here with One Shot, so we can be sure that the desired animation inside the Blend Tree are finished and not somewhere else
        AnimationTree.Connect(AnimationMixer.SignalName.AnimationFinished, new Callable(this, MethodName.AnimationTreeOnAnimationFinished),(uint)ConnectFlags.OneShot);
    }

    public override void _PhysicsProcess(double delta) {
        Player.Velocity = Player.Velocity.MoveToward(Vector3.Zero, Player.Deceleration * (float)delta);
        Player.MoveAndSlide();
    }

    public override async Task Exit() {
        await Task.CompletedTask;
    }
}
#

I await animation_finished whenever the attack state is set so I actually await the correct animation

loud marten
soft saffron
#

it does fire, but In the case of animation blending/mixing this might not be a clean solution

loud marten
#

Ahh gotcha. My solution would be to make the attack animation call a function that either resets your attack state or sends a signal for you to do so.

soft saffron
#

Yeah, I considered this as well

#

I guess I'll stay at my solution until it breaks

#

Thanks 🙂

loud marten
#

That's the best way 😌

#

no problem I wish I had a better answer lol.

soft saffron
#

There should be a signal for the state switch/transition nonetheless I think

loud marten
#

True. I'm sure with some magic you could code it in manually. but that's a lot of work

#

I did not see it when I was looking

soft saffron
#

polling could work, but not sure how you can ensure that

that in frame n you are in last frame of Attack
that in frame n+1 when the animation is logically finished to call a method
that in frame n+2 (Previous State again) simply does not check "is_attacking" again, otherwise you would have an infinite loop