How to stop the jumping animation from looping

v4.4.1.stable.official

I have been trying for hours to stop the AnimationPlayer from looping the jump animation.
No, the animation looping is not toggled in.
No matter what kind of code I implement, it just won’t stop looping.

Relevant code:
extends CharacterBody2D

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

func _process(float):
	# Get the input direction: -1, 0, 1.
	var direction := Input.get_axis("Move_Left", "Move_Right")
	
	#Flip the Sprite.
	if direction > 0:
		switch_direction(direction)
	elif direction < 0:
		sprite.flip_h = false
	
	#Apply movement.
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
	
	update_animations(direction)


#Plays animations.
func update_animations(direction):
	if is_on_floor():
		if direction == 0:
			if is_crouching:
				ap.play("Crouch")
			else:
				ap.play("Idle")
		else:
			ap.play("Walk")
	else:
		if velocity.y < 0:
			ap.play("Jump")
		elif velocity.y > 0:
			ap.play("Fall")

Once again. The loop is toggled off in the AnimationPlayer
Please help

How about you only play the jump animation when the jump button is pressed?

I tried that, but if I hold the button the animation would still loop

Use is_action_just_pressed instead of is_action_pressed.

Also please properly format your code by placing three backticks (```) before and after your code.

Do you use move_and_slide()? is_on_floor() won’t work correctly if you don’t use that function.

Handles jump.

if Input.is_action_just_released("Jump") and velocity.y < 0:
	velocity.y = JUMP_VELOCITY / 4
if Input.is_action_just_pressed("Jump") and is_on_floor():
	velocity.y = JUMP_VELOCITY

that’s the code for the jump
I have move_and_slide() in the physics process by default

yeah sorry, needless to say I’m pretty new.

I think it has something to do with the process function, but I don’t know how to solve it

clearly, the problem is that the animations are playing every frame.
but how do I fix that?

ok, yeah it can be solved doing this.
but how do I make fall not loop?

else:
		if velocity.y > 0:
			ap.play("Fall")
	if Input.is_action_just_pressed("Jump"):
		ap.play("Jump")

You call update_animations() every frame from _process(). Let’s assume your character is currently falling. That means velocity is greater than 0 and is_on_floor() is false. Now every frame you call ap.play("Fall"). The documentation for that method states:

The AnimationPlayer keeps track of its current or last played animation with assigned_animation. If this method is called with that same animation name, or with no name parameter, the assigned animation will resume playing if it was paused.

So at every frame you resume the fall animation. If it stopped at the last frame, you restart it by calling play("Fall") again.

I would suggest, that you introduce some kind of state for your character. For example:

enum PlayerState {IDLE, RUN, JUMP, FALL}
var current_state = PlayerState.IDLE
var previous_state = PlayerState.IDLE

At the start of your _process() function you set:

previous_state = current_state

And then after that you can set the state accordingly to what you want to happen.

if Input.is_action_just_pressed("Jump"):
		current_state = PlayerState.JUMP

Now you can compare if the current state has changed so you can then (and only then) switch to a different animation:

if current_state != previous_state:
   match (current_state):
      PlayerState.IDLE:
         ap.play("Idle")
      PlayerState.JUMP:
         ap.play("Jump")
      PlayerState.FALL:
         ap.play("Fall")

I hope this is helpful.

2 Likes

Oh thanks! I’ll try it out.