Help with Animation Control problems

Godot Version

4.6

Question

I keep running into animation control problems, sometimes an animation does not fire.

I use a pattern at the moment,

if state == States.STATE_NAME:
    if statename_timer == 0.0:
        animtree["parameters/playback"].travel("state_name")
    statename_timer = anim_timer(statename_timer,delta)
    
    if (statename_timer > statename_max_time) or (state_change_condition):
        state = States.OTHER_STATE
        statename_timer = 0.0

but i think this is more difficult to read and more complicated to code. Is there an easy way to just run animations and expect them to finish? What functions can i use like await() or anim_tree.animation_finished, to make the process more solid?

The reason is that i have a lot of characters and animations, they are hard to manage. There are things that require stopping the animation and blending to another animation from a pose.

I could also benefit from running the animation in an offline capacity to measure positions.

Im sure this question is hard to answer completely, but help with how to manage animation code is always welcome.

You haven’t really given us that much information about your architecture, so I’m going to infer what I can. But if my conclusions about what you are doing are wrong, well I’m working with what I’ve got.

Your state machine is too simple, and based on a push model, which both have issues. The first, is that your state machine code is going to get REALLY BIG. As its complexity grows, it’s going to become harder and harder to add new states and the problem you are facing now is going to multiply.

You will make your life a lot easier by making each state a separate script, and decoupling it from other states as much as possible. Doing so will solidify your thinking about each state and over time you will figure out the patterns necessary to keep your code from becoming unmanageable.

You can take a look at my State Machine Plugin, which is only two files and is very lightweight. It is a pull state machine however, and takes some getting used to; but when used correctly, states can be added and removed - even during runtime - without affecting the integrity of the machine.

Additionally, for what you are doing, your AnimationTree’s base should be an AnimationBlendSpace2D, not an AnimationStateMachine. You should have multiple AnimationStateMachines inside and blend them as appropriate. Doing so will simplify your state code, because the attack state doesn’t need to know about the move state. When the player swings a sword, the attack state triggers a state animation and a blend.

Tracking the AnimationTree animation_finished signal is the way to go for timing. You can also get the state name from that signal, so you can check to make sure its the animation you’re expecting to finish. (It doesn’t get triggered if an animation is stopped before finishing.)

The state machine should grow yes, at the moment ive managed to keep the states at a refined level but the animation switching is different … its a mess because some are done one way, and others are done that way. For example one NPC uses the above style, but the other switches animation states in an animate function and sets variables like ‘attacking’ and ‘reacting’ in the timed states.

Another problem is that there are interupt conditions like when the NPC gets damaged or an area zone triggers it to target the player -theres no safety check to see whether the animation playing needs to finish (could step both feet to the floor) and the code doesnt have the architecture to finish running the current animation and then act on the state change caused by the interupt.

Thanks I will definitely try to make an NPC type with the plugin. I spent over 2 hours setting up a character yesterday and there were many weird bugs slowing me down towards the end, so if that makes things clearer ill try it out.

That is a great idea, i think you have exactly solved one of the problems. Ive been using state machines even in the player code and then the state machine switches between BlendTree’s, so each one has idle and that mixes with the states animation, so theres a state for attack with a blendtree, another for walk, etc.

The states cant blend with other states … I was even confused and thinking about seeking the to the animation frame of the previous states idle animation.

Yeah i could blend them all with the Blendtree. I was planning to overhaul / refactor the animation system at some stage anyway. The animation states were just good for stability as they can be switched easily.

Im going to try this tomorrow and see what happens.

2 Likes

Your animation state should be completely decoupled from your entity’s logical state.

1 Like

How so?

I will tell the approach I follow which may be or maybe not the best for you but it works great for me.

1 - The controller keeps track of states.

2 - I check if a blocking animation is running to allow it to end before allow more actions in the controller.

3 - Depending on the state, update the movement

4 - Update the animation

I can share with you my repository implementing several controllers here https://github.com/walterpalladino/godot-tps-controller

I hope could be of use for you.

2 Likes

Animation is a visual effect. It doesn’t need to correspond to the logical state in a rigid one to one fashion. That’s the whole premise behind the usage of animation blending. Are you blending the logical state when you blend animations?

1 Like

When I saw TPS-Controller, all I could think of was this:

Ah, I see what you’re getting at here. And yes I am blending the logical states because I use multiple state machines in tandem. :smiley:

I’m not sure what are you trying to say. I first explained my approach and then allow him access to my implementation.
Sorry but I get lost.

Are you saying your state machines as capable of being e.g. 59.3% in the running state? And the rest distributed in a 3:2 ratio between idle and swimming states? :smile:

It’s a reference to the movie Office Space. That’s all.

Third person controllers are not called TPS in the US because that movie made TPS mean something else.

LOL More like 50% or maybe 33%. Lets take my Character 3D Plugin I’m currently revamping, which does both 1st person (FPS) and 3rd person (apparently TPS) controls.

As you can see, it currently has three StateMachines: Movement, Attack and Action. If the player is Jumping, Attacking, and Blocking, all three states are active - each in its own machine. All states are fully active, but each one makes up only ~33.33% of what the player is actually doing, and the animations are blended together.

The Jump controls the legs and feet, while the torso on up are taken over by the Attack animation, and then the left arm alone is controlled by the Block.

The code looks neat, is there an example anywhere showing how to use it?

I could probably at least use these for a game menu as mine is just a very basic placeholder at the moment.

Thanks those controllers are interesting, there were a couple of problems with the y-bot animations … i am using Godot 4.62 stable … the basic locomotion FBX got a red X in the file view, and a couple of the other … ok heres a list of apparently broken/ incompatible animations:

  1. mixamo-basic-locomotion.fbx
  2. mixamo-dancing.fbx
  3. mixamo-instruments.fbx
  4. mixamo-side-scroller.fbx
  5. mixamo-sword-and-shield.fbx

Also the tps scene didnt load.

The code looks decent, thanks for sharing.

Ive downloaded this and am checking it out.

The code refactor session turned into a fix up of some existing NPC problems … it can take all day …

1 Like

There is an example of how I use the state machine in my Character 3D Plugin. Though like I said, I’ve been revamping it. I can push the current unfinished version if you’d like so you can pull it.

I would take a look, i usually download as a zip from github at the moment as my PC is offline.

I have an idea for you about the Character controller … i couldnt see how to implement root motion.

I can upload a mixamo character with root motions if you need to test one.

In fact i think theres some root motion attacks and walk cycles in the free Quaternius pack.

When I originally created it, Godot didn’t support root motion yet. So I haven’t had a chance to play around with root motion at all in Godot or figure out how it’s different.

The way I would do it though is create say a RootMotionMovePlayerState and then have it handle things.

Sorry you have issues but I downloaded myself just now to test it and I have no none. Anyway, I hope you can solve your problem.