Attack Animation issue

Godot Version

Godot 4.6.2

Question

So when I hit the left mouse button, it’s supposed to do a little animation but it just do a little twitch and the animation does not finish. Please help guys.

If you share code, please wrap it inside three backticks or replace the code in the next block:

extends CharacterBody2D


const SPEED = 350.0
const JUMP_VELOCITY = -1000.0
@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var jumpsound: AudioStreamPlayer2D = $jumpsound


func _physics_process(delta: float) -> void:
	if abs(velocity.x) > 1:
		animated_sprite_2d.animation='run'
	else:
		animated_sprite_2d.animation='idle'
	if not is_on_floor():
		velocity += get_gravity() * delta
		animated_sprite_2d.animation='jump'
	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY
		jumpsound.pitch_scale = randf_range(0.9, 1.1)
		jumpsound.play()
	if Input.is_action_just_released("ui_accept") and velocity.y < 0:
		velocity.y *= 0.4
	if Input.is_action_just_pressed('attack'):
		animated_sprite_2d.animation='attack'
	# Get the input direction and handle the movement/deceleration.
	var direction := Input.get_axis("left", "right")
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()
	if direction==1:
		animated_sprite_2d.flip_h=false
	if direction==-1:
		animated_sprite_2d.flip_h=true

Hello, I think part of the problem might be in the first line I quoted here. I believe for input actions you need to include quotation marks not apostrophes. This follows the trend of other input actions in your code.

The animation instantly gets replaced by the run or idle animation from the process function. Try to comment out those animations to see if it stops the issue. Just as a test

This is your problem. You immediately overwrite the animation in the next physics frame. You need a condition that ignores this until the animation is finished.

Thanks but how do I do that?

You could add a boolean like “animation_locked” set to false. Then set it to true when starting the attack animation and false after the animation is finished.

Then in your process function add a check

if not animation_locked:

Do the run/idle animations

Here’s one way, but you might want to look into state machines.

extends CharacterBody2D

const SPEED = 350.0
const JUMP_VELOCITY = -1000.0

var is_jumping = false

@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var jumpsound: AudioStreamPlayer2D = $jumpsound


func _physics_process(delta: float) -> void:
	if not is_jumping:
		if abs(velocity.x) > 1:
			animated_sprite_2d.play("run")
		else:
			animated_sprite_2d.play("idle")
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY
		jumpsound.pitch_scale = randf_range(0.9, 1.1)
		jumpsound.play()
		is_jumping = true
		animated_sprite_2d.play("jump")
		animated_sprite_2d.animation_finished.connect(_on_jump_finished)
	if Input.is_action_just_released("ui_accept") and velocity.y < 0:
		velocity.y *= 0.4
	if Input.is_action_just_pressed('attack'):
		animated_sprite_2d.animation='attack'

	# Get the input direction and handle the movement/deceleration.
	var direction := Input.get_axis("left", "right")
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()
	if direction==1:
		animated_sprite_2d.flip_h=false
	if direction==-1:
		animated_sprite_2d.flip_h=true


func _on_jump_finished() -> void:
	animated_sprite_2d.animation_finished.disconnect(_on_jump_finished)
	is_jumping = false

Also keep in mind you don’t have to set the pitch in code and can use an AudioStreamRandom inside your AudioStreamPlayer to handle it instead. You should also make a “jump” action instead of using “ui_accept”

1 Like

Thanks for the tips but I got an error: E 0:00:05:878 player.gd:28 @ _physics_process(): Signal ‘animation_finished’ is already connected to given callable ‘CharacterBody2D(player.gd)::_on_jump_finished’ in that object.
<C++ Error> Method/function failed. Returning: ERR_INVALID_PARAMETER
<C++ Source> core/object/object.cpp:1650 @ connect()
player.gd:28 @ _physics_process()

Also it looks like this now:

https://youtu.be/tMtLOTo6D7c

extends CharacterBody2D

const SPEED = 350.0
const JUMP_VELOCITY = -1000.0

var is_jumping = false

@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var jumpsound: AudioStreamPlayer2D = $jumpsound


func _physics_process(delta: float) -> void:
	if not is_jumping:
		if abs(velocity.x) > 1:
			animated_sprite_2d.play("run")
		else:
			animated_sprite_2d.play("idle")
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor() and not is_jumping:
		velocity.y = JUMP_VELOCITY
		jumpsound.pitch_scale = randf_range(0.9, 1.1)
		jumpsound.play()
		is_jumping = true
		animated_sprite_2d.play("jump")
		animated_sprite_2d.animation_finished.connect(_on_jump_finished)
	if Input.is_action_just_released("ui_accept") and velocity.y < 0:
		velocity.y *= 0.4
	if Input.is_action_just_pressed('attack'):
		animated_sprite_2d.animation='attack'

	# Get the input direction and handle the movement/deceleration.
	var direction := Input.get_axis("left", "right")
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()
	if direction==1:
		animated_sprite_2d.flip_h=false
	if direction==-1:
		animated_sprite_2d.flip_h=true


func _on_jump_finished() -> void:
	animated_sprite_2d.animation_finished.disconnect(_on_jump_finished)
	is_jumping = false

See if that works, but I recommend you figuring out the changes I made and seeing if you can fix it before posting an error or you’re not going to get very far.

Alright thanks