Code Help: One Frame Attacking Animation

Godot Version

4.2.1.stable

Question

I need help adding an attack animation/state machine this code. Anytime before ive tried it only plays the first frame of the animation. Here’s the code. `extends CharacterBody2D

@export var speed: int = 35
@onready var animations = $AnimationPlayer
@onready var animationTree : AnimationTree = $AnimationTree

enum State {
MOVE,
ROLL,
ATTACK
}

var state: State = State.MOVE

func _physics_process(delta):
match state:
State.MOVE:
move_state(delta)
move_and_slide()
State.ROLL:
# Handle roll state logic (if needed)
pass
State.ATTACK:
# Handle attack state logic (if needed)
pass

func move_state(delta):
var moveDirection = Input.get_vector(“ui_left”, “ui_right”, “ui_up”, “ui_down”)
velocity = moveDirection * speed

if velocity.length() == 0:
	animations.stop()
else:
	var direction = getMovementDirection(moveDirection)
	animations.play("walk" + direction)

func getMovementDirection(moveDirection: Vector2) → String:
var direction = “Down”
if moveDirection.x != 0 or moveDirection.y != 0:
if abs(moveDirection.x) > abs(moveDirection.y):
if moveDirection.x < 0:
direction = “Left”
else:
direction = “Right”
else:
if moveDirection.y < 0:
direction = “Up”
else:
direction = “Down”
return direction

`

You’re calling animations.play() every frame which I think resets the animation every frame, that’s why you’re only seeing the first frame of it.
Try only calling play() if it’s not already playing. Something like:

if velocity.length() == 0:
    if animations.is_playing():
	    animations.stop()
else:
	var direction = getMovementDirection(moveDirection)
    if not animations.is_playing() or animations.current_animation != "walk" + direction:
	    animations.play("walk" + direction)
1 Like

Hello thank you could you try fixing this also please. I did you r fix and now I just stop moving when I press attack. `extends CharacterBody2D

@export var speed: int = 35
@onready var animations = $AnimationPlayer
@onready var animationTree : AnimationTree = $AnimationTree

enum State {
MOVE,
ROLL,
ATTACK
}

var state: State = State.MOVE

func _physics_process(delta):
match state:
State.MOVE:
move_state(delta)
move_and_slide()
State.ROLL:
# Handle roll state logic (if needed)
pass
State.ATTACK:
attack_state(delta)
pass

func move_state(delta):
var moveDirection = Input.get_vector(“ui_left”, “ui_right”, “ui_up”, “ui_down”)
velocity = moveDirection * speed

if velocity.length() == 0:
	if animations.is_playing():
		animations.stop()
else:
	var direction = getMovementDirection(moveDirection)
	if not animations.is_playing() or animations.current_animation != "walk" + direction:
		animations.play("walk" + direction)

if Input.is_action_just_pressed("attack"):
	state = State.ATTACK

func attack_state(delta):
# Check if attack animation is not playing
if not animations.is_playing():
# Determine attack animation based on movement direction
var attackAnimation = getAttackAnimation()
# Play the determined attack animation
animations.play(attackAnimation)

	# Check if the attack animation has finished playing
	# Use 'current_animation' to get the name of the currently playing animation
	if animations.current_animation == attackAnimation:
		state = State.MOVE

func getMovementDirection(moveDirection: Vector2) → String:
var direction = “Down”
if moveDirection.x != 0 or moveDirection.y != 0:
if abs(moveDirection.x) > abs(moveDirection.y):
if moveDirection.x < 0:
direction = “Left”
else:
direction = “Right”
else:
if moveDirection.y < 0:
direction = “Up”
else:
direction = “Down”
return direction

func getAttackAnimation() → String:
var attackAnimation = “attackRight” # Default attack animation

if velocity.length_squared() > 0:
	if abs(velocity.x) > abs(velocity.y):
		if velocity.x < 0:
			attackAnimation = "attackLeft"
		else:
			attackAnimation = "attackRight"
	else:
		if velocity.y < 0:
			attackAnimation = "attackUp"
		else:
			attackAnimation = "attackDown"

return attackAnimation

` thank you

Well, if you press “attack” you change state = State.ATTACK, so this is to be expected: your movement code is only run if state == State.MOVE.

Also, please make sure to format your code properly (by clicking the “</>” in the editor window when composing a post). Otherwise, it’s really hard to read. You can make sure that it’s looking correct by checking the preview on the right.

Thank you, however the attack animation doesn’t play. The walk animation just keeps going.

Yeah, because you’re switching back to the move state right away:

func attack_state(delta):
    # ...
    # Check if the attack animation has finished playing
    if animations.current_animation == attackAnimation:
        state = State.MOVE

This doesn’t check if the “animation has finished playing”, but only if the currently played animation is equal to the attackAnimation!