Wanting my Dash animation to Play when Dashing, but it only plays the first frame the whole time

Godot Version
4.4.1

Question

I’m brand new to coding, and in my 2D Platformer I have a dash animation, but it only plays the first frame of it the whole time one holds the dash key and moves left or right. I want it to play the whole animation. Idk if this is an animation player or a coding problem, but it appears and plays normal in the animation player.

Here is the code for the player character and initializing the animations:
(((Tool-less refers to the character’s actions without any tools equipped)))

extends CharacterBody2D

@onready var animation = $AnimationPlayer
@onready var sprite = $Sprite2D

@export var jog_speed: float = 100.0
@export var dash_speed: float = 300.0
@export var jump_velocity: float = -400.0
@export var jump_time: float = 0.25
@export var gravity_force: float = 3.0

var gravity = ProjectSettings.get_setting(“physics/2d/default_gravity”)
var is_jumping : bool = false
var jump_timer : float = 0
var is_dashing = false

func _physics_process(delta: float) → void:
if Input.is_action_pressed(“Jog Left”):
sprite.scale.x = abs(sprite.scale.x) * -1
if Input.is_action_pressed(“Jog Right”):
sprite.scale.x = abs(sprite.scale.x)

# Add the gravity.
if not is_on_floor() and not is_jumping:
	velocity.y += gravity * gravity_force * delta
	


# Handle jump.
if Input.is_action_just_pressed("Jump") and is_on_floor():
	velocity.y = jump_velocity
	is_jumping = true
	
	
elif Input.is_action_just_pressed("Jump") and is_jumping:
	velocity.y = jump_velocity

if is_jumping and Input.is_action_pressed("Jump") and jump_timer < jump_time:
	jump_timer += delta
else:
	is_jumping = false
	jump_timer = 0


# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var direction := Input.get_axis("Jog Left", "Jog Right")
if direction:
	velocity.x = direction * jog_speed
else:
	velocity.x = move_toward(velocity.x, 0, jog_speed)
	

if Input.is_action_pressed("Run"):
	if direction:
		velocity.x = direction * dash_speed
		
	else:
		velocity.x = move_toward(velocity.x, 0, dash_speed)
		


	
	

update_animation()
move_and_slide()

func update_animation():
if velocity.x != 0:
animation.play(“Jog - Tool-less”)
else:
animation.play(“Idle - Tool-less”)

if Input.is_action_pressed("Run") and velocity.x < 0:
	animation.play("Dash - Tool-less")
if Input.is_action_pressed("Run") and velocity.x > 0:
	animation.play("Dash - Tool-less")
	


if velocity.y < 0:
	animation.play("Jump - Tool-less")

Please post your code as pre-formatted text. You can do this by placing three backticks (```) before and after your code. This preserves indentation.

func update_animation():
	if velocity.x != 0:
		animation.play(“Jog - Tool-less”)
	else:
		animation.play(“Idle - Tool-less”)

	if Input.is_action_pressed("Run") and velocity.x < 0:
		animation.play("Dash - Tool-less")
	
	if Input.is_action_pressed("Run") and velocity.x > 0:
		animation.play("Dash - Tool-less")
		
	if velocity.y < 0:
		animation.play("Jump - Tool-less")

update_animation is called every time _physics_process is called. Godot calls _physics_process many times a second.

If the Run button is held when update_animation is called, the first condition that is checked is whether the velocity is unequal to zero. This is the case, so the animation "Jog - Tool-less" is set. The remaining conditions are then checked from top to bottom.

The dash animation is set in one of the subsequent conditional checks. However, update_animation is called again shortly after the function is exited, and so the animation is first set to Jog - Tool-less again. This is why you only see one frame of the dash animation.

So if I’m getting what you’re saying correctly, I need to change the code for the “Dash - Tool-less” animation to be called? Or do I need to change the order of the play animation codes?
Sorry, but I’m new to all of this so I’m a bit confused by the wording

I believe @TokyoFunkScene has identified two problems that you need to address.

The first is that you are setting a new animation every frame. That is preventing the last animation you call from completing. This is why you are only seeing the first frame. You can use AnimationPayer.is_playing() to wait for the animation to complete.

is_playing method

The second issue is in your logic. You play two different animations when velocity.x is not zero. Something like this will fix that problem:

if velocity.x != 0:
  if Input.is_action_pressed("Run"): 
    animation.play("Dash - Tool-less")
  else:
    animation.play(“Jog - Tool-less”)

Fair warning - comparing floats to a value is problematic.

Pertinent bit:

You should usually use the @GlobalScope.is_equal_approx() and @GlobalScope.is_zero_approx() methods instead of == to compare float values for equality.