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!