My attack animation only plays the first frame

Godot Version

Node2D.gd:

extends Node2D

func play_idle():
	%AnimationPlayer.play("idle")


func play_run():
	%AnimationPlayer.play("run")


func play_attack():
	%AnimationPlayer.play("side_attack")

player.gd:

extends CharacterBody2D


func _physics_process(delta):
	var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	velocity = direction * 600
	move_and_slide()
	
	if velocity.length() > 0.0:
		%Bluwee.play_run()
	else:
		%Bluwee.play_idle()
	
	if Input.is_action_pressed("attack"):
		%Bluwee.play_attack()

Question

My attack animation is only playing the first frame, I don’t really know why this is happening, but maybe it’s because of the idle animation.

The problem is that it gets overwritten by you idle or run animation. you should add a variable to keep track of your animation:

var attacking: bool = false

func _physics_process(delta):
	var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	velocity = direction * 600
	move_and_slide()
	
	if velocity.length() > 0.0 and not attacking:
		%Bluwee.play_run()
	elif not attacking:
		%Bluwee.play_idle()
	
	if Input.is_action_just_pressed("attack") and not attacking:
		attacking = true
		%Bluwee.play_attack()

and then you need to connect the animation_finished signal of the animation_player to the script to detect when the attack animation is finished:

func _on_animation_finished(animation: String):
	if animation == "side_attack":
		attacking = false
1 Like

Thank you that works, but now it’s stuck at the end of the animation and doesn’t go back to idle animation.

have you connected the animation_finished-signal from the animationplayer?

yes, I have added it. This is how it is:

extends CharacterBody2D

var attacking: bool = false

func _physics_process(delta):
	var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	velocity = direction * 600
	move_and_slide()
	
	if velocity.length() > 0.0 and not attacking:
		%Bluwee.play_run()
	elif not attacking:
		%Bluwee.play_idle()
	
	if Input.is_action_just_pressed("attack") and not attacking:
		attacking = true
		%Bluwee.play_attack()


func _on_animation_finished(animation: String):
	if animation == "side_attack":
		attacking = false

but it’s still stuck on the last frame

Hi there! :slight_smile:
You can try a signal to ensure your “_on_animation_finished” function is called whenever an animation finishes. Like this:

func _ready():
%Bluwee.connect(“animation_finished”, Callable(self, “_on_animation_finished”))

Cheers!

I just tried it, but it also doesn’t work :sob:

Maybe this will work?

func _on_animation_finished(animation: String):
	if animation == "side_attack":
		attacking = false
		%Bluwee.play_idle()

It still doesn’t work, it’s really weird. I even tried adding an animation stop to the function:

func _on_animation_finished(animation: String):
	if animation == "side_attack":
		attacking = false
		%Bluwee.play_idle()
		%Bluwee.stop_idle()

Do I need to call the function or smth? Or maybe I should put the animation transition isnide the _physics_process() function?

can you put a print inside this method to test if it gets called?

func _on_animation_finished(animation: String):
	print("Animation finished: ", animation)
	if animation == "side_attack":
		attacking = false
		%Bluwee.play_idle()

Oh yh, it doesn’t print the message

then you didnt connect the signal

try using this one

if Input.is_action_pressed("attack"):
	%Bluwee.play_attack()
elif velocity.length() > 0.0:
	%Bluwee.play_run()
else:
	%Bluwee.play_idle()

My Code Explaination:
i this way the whole if else structure become ones first it check for Input for attack button if it happen it end the if else structure after running the attack.
if attack button was not pressed it check for velocity length. if this is true then it run the player until the 2nd condition is false if nothing is doing it becomes idle.

Issue in your code
the problem in your code is you are using two if else structure one for running and one for attack you code stuck after one attack because you are check for run or idle and attack at same time. so after every frame event if you press the attack button your attack animation is over-ridden by ilde or run animation.

The problem with your code is that when he stops pressing attack but is still inside attack animation he stops the animation and continues with walk or idle

he stops the animation and continues with walk or idle what does this mean I did not get it. I guess this is what you want. or if you share the screenshot may be it explain well.

this method gets called every frame, so as soon as the attack button is released the animation will change because this attack-condition is no longer met, eventhough the attack-animation might still be playing.
Thats why you need to wait for the attackanimation to finish before you change the animation

got it. wait untill I came up with a solution.

The problem is already solved. He just has to connect the signal

2 Likes

Glad to here it. But I got two solution. one is too use State Machine and other is disable looping in your animation for attack animation.

how would I do that? I haven’t used signals before