Syntax help, end of an animation.

DullahanDullahan Posts: 9Member

What would be the correct syntax to know when an animation ends so that only after starting the next?

Because in this my case, the Attack animation is being cut and is not coming to an end, so how would it be correct to not cut attack the animation and show the animation attack correct?

I am using separate Sprites and not a SpriteSheet file.

Code in Pastbin in link:

https://pastebin.com/MQJMpm0F


Tags :

Best Answer

  • TwistedTwiglegTwistedTwigleg Posts: 1,408
    edited August 14 Accepted Answer

    If you are using an AnimatedSprite or AnimationPlayer node, then the animation_finished signal (AnimatedSprite documentation ) will be triggered when the animation ends. If I remember correctly, if your animation loops then the animation_finished signal will only trigger upon the completion of the first loop.


    Looking at your code, most likely the reason the attack animation gets cut off is because another animation, likely either Idle or Walk, gets call through the play function before the attack animation has a chance to finish.
    If this is the case, there are many different ways to go about working around this issue.

    One of the easiest ways is to have a variable that "locks" the animation until finished. For example, to add animation locking with the code above (untested):

    extends KinematicBody2D
    
    const SPEED = 300
    const GRAVITY = 40
    const NORMAL = Vector2(0, -1)
    const FORCA_JUMP = -800
    var motion = Vector2()
    var screen_size
    var animation_locked = false
    
    
    func _ready():
        screen_size = get_viewport().size
        # Connect the signal to the _on_animation_finished_function
        $Sprite.connect("animation_finished", self, "_on_animation_finished")
    
    
    func _physics_process(delta):
        _movimento()
    
    
    func _movimento():
        motion.y += GRAVITY
    
        #LEFT AND RIGHT
        if Input.is_action_pressed("ui_left"):
            motion.x = -SPEED
            _change_animation("Walk", false)
        elif Input.is_action_pressed("ui_right"):
            motion.x = SPEED
            _change_animation("Walk", true)
        else:
            motion.x = 0
            _change_animation("Idle")
    
        # ATTACK
        if Input.is_action_just_released("ui_down"):
            _change_animation("Golpe_1")
            # Lock the animation
            animation_locked = true
    
        #JUMP
        if is_on_floor():
            if Input.is_action_just_pressed("ui_up"):
                motion.y = FORCA_JUMP
        else:
            # Unlock the animation, so jump always interrupts whatever is playing
            animation_locked = false
            _change_animation("Jump")
    
    
        motion = move_and_slide(motion,NORMAL)
    
    
    func _change_animation(animation_name, sprite_flip_h=null):
        # Only change the animation if the animation is NOT locked
        if animation_locked == false:
            $Sprite.play(animation_name)
            # Flip the sprite if the sprite_flip_h argument is not null
            if sprite_flip_h != null:
                $Sprite.flip_h = sprite_flip_h
    
    
    # This should work if you are using an AnimatedSprite node.
    # If you are using an AnimationPlayer node, you will need
    # to define it as follows:
    # func _on_animation_finished( finished_anim_name )
    func _on_animation_finished():
        # Unlock the animation
        animation_locked = false
    

    The code above should only change animations after the animation_locked variable is set to false, so setting it to true when the attack animation plays should allow the attack animation to play fully before it is changed. This method works pretty well if you don't need to know what animation is playing, but rather just whether the animation should be overridden or not.
    This method works fairly well. It is not ideal for all games or projects, however depending on the needs of your project, it might work just fine.

    If you want something with a little more control, writing a simple state machine might really help. Anymore, I almost always write a simple state machine to handle animations, as I find it gives flexibility to control the behavior and transitions between animations without having to write dozens of conditions strewn through the code base. That said, state machines are a bit more complicated and for some projects might be a tad overkill.
    If you want to use a state machine, this video by Game Endeavor seems to be similar to the types of animation state machines I write for my projects:

    Hopefully this helps!

Answers

  • TwistedTwiglegTwistedTwigleg Posts: 1,408Admin
    edited August 14 Accepted Answer

    If you are using an AnimatedSprite or AnimationPlayer node, then the animation_finished signal (AnimatedSprite documentation ) will be triggered when the animation ends. If I remember correctly, if your animation loops then the animation_finished signal will only trigger upon the completion of the first loop.


    Looking at your code, most likely the reason the attack animation gets cut off is because another animation, likely either Idle or Walk, gets call through the play function before the attack animation has a chance to finish.
    If this is the case, there are many different ways to go about working around this issue.

    One of the easiest ways is to have a variable that "locks" the animation until finished. For example, to add animation locking with the code above (untested):

    extends KinematicBody2D
    
    const SPEED = 300
    const GRAVITY = 40
    const NORMAL = Vector2(0, -1)
    const FORCA_JUMP = -800
    var motion = Vector2()
    var screen_size
    var animation_locked = false
    
    
    func _ready():
        screen_size = get_viewport().size
        # Connect the signal to the _on_animation_finished_function
        $Sprite.connect("animation_finished", self, "_on_animation_finished")
    
    
    func _physics_process(delta):
        _movimento()
    
    
    func _movimento():
        motion.y += GRAVITY
    
        #LEFT AND RIGHT
        if Input.is_action_pressed("ui_left"):
            motion.x = -SPEED
            _change_animation("Walk", false)
        elif Input.is_action_pressed("ui_right"):
            motion.x = SPEED
            _change_animation("Walk", true)
        else:
            motion.x = 0
            _change_animation("Idle")
    
        # ATTACK
        if Input.is_action_just_released("ui_down"):
            _change_animation("Golpe_1")
            # Lock the animation
            animation_locked = true
    
        #JUMP
        if is_on_floor():
            if Input.is_action_just_pressed("ui_up"):
                motion.y = FORCA_JUMP
        else:
            # Unlock the animation, so jump always interrupts whatever is playing
            animation_locked = false
            _change_animation("Jump")
    
    
        motion = move_and_slide(motion,NORMAL)
    
    
    func _change_animation(animation_name, sprite_flip_h=null):
        # Only change the animation if the animation is NOT locked
        if animation_locked == false:
            $Sprite.play(animation_name)
            # Flip the sprite if the sprite_flip_h argument is not null
            if sprite_flip_h != null:
                $Sprite.flip_h = sprite_flip_h
    
    
    # This should work if you are using an AnimatedSprite node.
    # If you are using an AnimationPlayer node, you will need
    # to define it as follows:
    # func _on_animation_finished( finished_anim_name )
    func _on_animation_finished():
        # Unlock the animation
        animation_locked = false
    

    The code above should only change animations after the animation_locked variable is set to false, so setting it to true when the attack animation plays should allow the attack animation to play fully before it is changed. This method works pretty well if you don't need to know what animation is playing, but rather just whether the animation should be overridden or not.
    This method works fairly well. It is not ideal for all games or projects, however depending on the needs of your project, it might work just fine.

    If you want something with a little more control, writing a simple state machine might really help. Anymore, I almost always write a simple state machine to handle animations, as I find it gives flexibility to control the behavior and transitions between animations without having to write dozens of conditions strewn through the code base. That said, state machines are a bit more complicated and for some projects might be a tad overkill.
    If you want to use a state machine, this video by Game Endeavor seems to be similar to the types of animation state machines I write for my projects:

    Hopefully this helps!

  • DullahanDullahan Posts: 9Member
    edited August 14

    @TwistedTwigleg

    That helped a lot. Now is fully running the animation.

    And as for the State of Machine, I've seen some things about it, however my English is not good and much that goes on in these videos I just don't understand correctly to use.

    Very thank.

Sign In or Register to comment.