3
\$\begingroup\$

I am learning Godot 3.0 and I have a question concerning animation.

I have a player object whose node structure is KinematicBody2D > Sprite > AnimationPlayer. In the AnimationPlayer, I have ascend and descend animations that I want to play until their final frames, at which point I want to hold on those frames.

For now, I initiate my animations using the following function, which looks at my player's state attribute:

func animate():
    var animation_player = $Sprite.get_node("AnimationPlayer")

    # image matches orientation
    if orientation == "LEFT":
        $Sprite.flip_h = true
    else:
        $Sprite.flip_h = false

    # animation depends on state    
    if state == "idle":
        if not ["idle"].has(animation_player.current_animation):
            animation_player.play("idle")   

    if state == "run":
        if not ["run"].has(animation_player.current_animation):
            animation_player.play("run")        

    if state == "ascend":
        if not ["ascend"].has(animation_player.current_animation):
            animation_player.play("ascend")

    if state == "descend":
        if not ["descend"].has(animation_player.current_animation):
            animation_player.play("descend")            

I have disabled looping for my ascend and descend animations and yet they still loop. Probably because when their animation finishes, the idle animation starts and is then immediately changed back to ascend or descend since the player is still in this state.

So my question is: How do I go about holding on the final frame of certain animations?


I have looked into the animation_finished() signal of the AnimationPlayer, but I can't figure out how to use it properly.

All I can think to do is use a Call Func track on the ascend and descend animations, calling a custom function at the end of these animations which switches to a different, single-frame but looped animation (ascend_static or descend_static). But surely there is a better way?

\$\endgroup\$
  • \$\begingroup\$ Where do you call animate and change the state? \$\endgroup\$ – skrx Mar 6 '18 at 15:26
  • \$\begingroup\$ I have a _process_physics() method that first calls a custom input_processing() method (in which states are changed), then calls animate(), and then does physics and positioning. Some of these should probably be in _process() which I don't currently use. Any restructuring advice is appreciated. \$\endgroup\$ – GoldenGremlin Mar 6 '18 at 17:16
  • \$\begingroup\$ I also change states with function calls at the end of nonlooping animations. \$\endgroup\$ – GoldenGremlin Mar 6 '18 at 17:19
2
\$\begingroup\$

I think the problem is that you call your animate function in every loop. This leads to a constant restart of the finished loop. If you wouldn't check whether or not the animation is running your animation would restart over and over again.

I think it is better to put the animate function into the setter function of state, which is called whenever your variable is changed. To do this, just add the following line to your script:

var state = "idle" setget state_change

And the function:

func state_change(new_state):
    state = new_state
    animate(state)

The state_change function is only called when the state changes and therefore the animate function is only called once (you also don't have to check for a running animation anymore). Since you probably want to loop your idle animation, you have to make sure that this animation is set to loop.

\$\endgroup\$
  • \$\begingroup\$ Wow, I never thought to create a setter function for my state variable. Brilliant. Thanks. \$\endgroup\$ – GoldenGremlin Mar 9 '18 at 2:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.