Newb here, how do i get my attack animation to play?

Godot Version

godot-4

Question

I’m trying to make a very basic rogue-like game. I have a character who i need to attack when i press the spacebar, however it only plays the first frame very quickly. The animation works and the spacebar is mapped correctly. Any ideas? i’ll post my character code below (sorry if it is formatted poorly):

extends CharacterBody2D

var speed = 80.0
@onready var animations = $AnimatedSprite2D
var died = false
@onready var animation_player = $AnimationPlayer

func _ready():
pass

func _process(delta):
var velocity = Vector2.ZERO

if died:
	return

var direction = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
if direction > 0:
	animations.flip_h = false
elif direction < 0:
	animations.flip_h = true

if Input.is_action_pressed("ui_right"):
	velocity.x += 1
elif Input.is_action_pressed("ui_left"):
	velocity.x -= 1
if Input.is_action_pressed("ui_down"):
	velocity.y += 1
elif Input.is_action_pressed("ui_up"):
	velocity.y -= 1

if Input.is_action_just_pressed("attack"):
	animation_player.play("attack")

if velocity != Vector2.ZERO:
	velocity = velocity.normalized() * speed * delta
	move_and_collide(velocity)
	animations.play("walk")
else:
	animations.play("idle")

func _on_mace_hit_area_entered(area):
if area.is_in_group(“hurtbox”):
area.take_damage()

1 Like

Hey, I’m new as well and have only worked in 3d, so take what I say with an absolute block of salt, but I believe you need to change the else in the velocity statement at the bottom with a elif that checks if an animation is currently playing. I THINK that should fix it. Because, I think what’s happening is, since this is the process function, all that code is called every frame, and you play the idle animation every frame, so when you play the attack animation, it is interrupted by the idle one. Try this out and let me know if it works!

You have both an AnimatedSprite2D and AnimationPlayer ? Like @Bubba said, I suppose the “walk”/“idle” animations might be overriding the “attack” animation.

1 Like

Why is using AnimationSprite2D with AnimationPlayer bad? How do you synchronize all your AnimationPlayer animations (like other property changes) with the Sprite2D’s animations (and still load animation frames with SpriteFrames)?

I don’t know your full use case, but the AnimatedSprite2D node is a helper to make sprite animations simple and avoid using the AnimationPlayer. If you want to use the AnimationPlayer, I would probably do everything with it.

This official tutorial is good at showing how to do it in one way or another, but not at the same time :

Could you show us what the AnimationPlayer is doing ? (e.g. the timeline of the “attack” animation and your scene hierarchy)

Changing that else to an elif has gotten me closer. Now the attack animation actually plays, but it will play forever until another input is given. Also, the idle animation no longer appears. Thanks for you help!


Heres a screenshot of my animation player. I’m using it to create hitboxes for my attack animation. There are two hitboxes because in one attack, the animation swings twice. The animation is only 1 second long but i have to admit I’m not very familiar with it. Have I missed something?

Oh, well if you still haven’t figured it out, post another sc of your code and I’d be glad to take another look if you’d like.

You will probably need to disable or stop the AnimatedSprite2D while the AnimationPlayer plays.

if Input.is_action_just_pressed("attack"):
	animation_player.play("attack")
	animations.stop()

Next make sure you aren’t overriding the animation player’s frames

if not animation_player.is_playing():
	if velocity != Vector2.ZERO:
		velocity = velocity.normalized() * speed * delta
		move_and_collide(velocity)
		animations.play("walk")
	else:
		animations.play("idle")

Using debug > visible collision shapes might help to debug this more.

gertkeno that helped so much, its finally working! Thank you!