+3 votes

So I'm following a Youtube tutorial, and I've set up player character as a KinematicBody2D with a simple state machine and AnimationPlayer that has an animation for each State/direction combination the character can be in (AttackUp, AttackRight, RunDown, IdleLeft, etc.).

Basically, if the player hits space, he enters the attack state and goes into the ATTACK state in physicsprocess(). Inside the attack_state() method, an AnimationTree plays the appropriate attack animation in the AnimationPlayer.

During each attack animation(Attack Up, Attack Down, Attack Left, Attack Right), I have a track that calls a method named attackanimationfinished() when the animation is done. This method changes the player state back to MOVE.

AnimationPlayer

(In the move_state function, the state gets changed to ATTACK if the player presses the space bar. I would paste it in but it doesn't format in very readable manner.

func _physics_process(delta):
  match(state):
    MOVE:
        move_state(delta)
    ROLL:
        pass
    ATTACK:
        attack_state()

func attack_state():
  print("Inside attack_state()")
  velocity = Vector2.ZERO
  animation_state.travel("Attack")

func attack_animation_finished():
  print("Inside attack_animation_finished()")
  state = MOVE

I put in print() statements to both attack methods to illustrate what I'm talking about.

As you can see, the AnimationPlayer only calls the method once. However, when I play the game and attack, this happens:

Method called twice.

The method is being called twice for some reason.

Now, I don't really understand why the first print() statement is being called so many times either. I assume it has something to do with the length of the animation? I can wrap my head around that, but I can't understand why the second print() statement is executing twice.

The code for this method clearly sets the state back to MOVE, so it shouldn't be making a second pass. Regardless, the game is set up so that the only way the method can be called is through the AnimationPlayer, and the AnimationPlayer can only play it if attack_state() is called!

This isn't causing any actual bugs or weird behaviors at all, it's just something that I noticed when I was debugging my animations. It however is very weird to me. Why is my AnimationPlayer calling this method twice?

Does it have something to do with the fact I'm playing these animations by using an AnimationTree?

in Engine by (20 points)
edited by

Now, I don't really understand why the first print() statement is being called so many times either.

It's being called so many times because the _physics_process() function is called every time the physics calculations are done. Depending upon your hardware, this is several times a second.

I understand that, but why is attackanimationfinished() being called twice? The method clearly changes the state to MOVE and, not only that, but the only way to get to that method is through the attackstate() method, so if attackanimationfinished() were to print twice, wouldn't it require for a second pass of attackanimation(), which would another series of "Inside attack_state()" messages in the output window?

Maybe there's some function which is getting called faster than the _physics_process() function. Is some of this code tied to the _process() function? Maybe that's a bit faster than _physics_process()?

So after using the debugger, I was able to pinpoint the exact moment it goes back to attackanimationfinished(). It was right after the process() callback in my Global singleton script (That's the only script in my game that uses _process() right now). WHY it goes directly from _process() to attackanimationfinished(), I have no idea. Right now, I (as a Godot novice) am thinking it is somehow related to the AnimationTree that is calling attackanimation_finished(). Some people have told me it's better to use a signal for that, so maybe I'll try that again (I tried before, but for some reason it was causing my game to freeze. I'll probably try again with the debugger to see what was causing that).

maybe it happen when you do diagonal attack e.g. right + up , both animation attack state get called and when finish it called twice

If you ever find a satisfactory answer to this I'd love to know. I followed HeartBeast's tutorial as well and based a lot of my enemies' actions on using the call_method trick (because there's no other way to know when an AnimationTree's animations are done playing...), and my functions are getting called 3-4 times. I'm experiencing weird behavior which might not be that, but I also have other lines of code like timers and such packed into that end-of-animation method call, so I'd rather it not get called several times.

_process() function makes the situation worse, getting called 3-4 times.

I found that calling the script 0.1-0.2 seconds before the end of the animation instead of right at the end relieved a lot of my issues.

5 Answers

0 votes

I have the same issue, and I can't resolve it since there's maybe a bug with finished_animation signal so I don't have a solution at the moment...

First time stuck with godot... Don't know what to do :'(

by (30 points)
0 votes
func attack_animation_finished():
    print("attack_animation_finished....." + str(state))
    if state == ATTACK:
        velocity = Vector2.ZERO
        state = MOVE

func animation_test():
    print("the animation test......." + str(state))

func animation_test_start():
    print("the animation test start......." + str(state))

add function animation_test to 0.2s, add function animation_test_start to 0.0s
output result:

the animation test start.......2
the animation test.......2
attack_animation_finished.....2
attack_animation_finished.....0

animation_test and animation_test_start just call once, attack_animation_finished always tiwce.

I think this is the bug of the engine.

by (14 points)
0 votes

You connected your method to both Call Method track and AnimationPlayer animation_finished signal.

by (886 points)
0 votes

I've had this exact issue. It seems to occur when the called method is right at the end of the animation.

Setting the function to be called before the end of the animation solves this quirk/bug of the engine

by (14 points)
0 votes

Sorry for my English, Im not native speaker, but after some experiments I think i figured out the solution of problem. Most important, it calls method twice only if it placed in the end of animation. If you put it for 0.3 seconds before the end it works approprietly.
My suggestion is that in animationTree's "travel" mode it literaly travels through the path you made. For example, if "Attack" animation or blend space placed between "Idle" and "Run" animations(or blend space) it executes all the animations that placed directly at the beggining and at the end of attack animation. The mechanism of animationTree is "gluing" animation based on travel path and it misses animation between current animation and target animation, but cant miss function that placed at the edges. So thats why when you change animation from attack to idle, for example, it calls it once and then again becouse now its placed between the path

by (14 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.