Need some help regarding the animations from AnimatedSprite2D

Godot Version

4.2.2

Question

I am working on my first game and I wanted to integrate some animations I made using Aseprite. I ran into some issues, and needed help with them.

###ISSUE : 1
There is a animation I want to play before the jump is intiated (the takeoff animation). I have another animation during jump when in the air. The takeoff animation only playes the first frame and gets cutoff.
Animation:
Playertf
What happens in game:
2024-08-1016-42-58-ezgif.com-video-to-gif-converter (3)

###ISSUE 2:
The wall slide animation dosent play.
Animation:
Playerws
What happens In game:2024-08-1016-42-58-ezgif.com-video-to-gif-converter (2)

###ISSUE 3:
I want to play an animation when the player lands on the ground, like a landing animation after a jump, but I couldnt get the logic for it. I tried some things but they didnt work.
Animation:
Playertf

This is the player code:


var Speed = 300.0
var direction = 1

@export var jump_height : float = 150
@export var jump_time_to_peak : float = 0.45
@export var jump_time_to_descent : float = 0.39

@onready var jump_velocity : float = ((2.0 * jump_height) / jump_time_to_peak) * -1.0
@onready var jump_gravity : float = ((-2.0 * jump_height) / (jump_time_to_peak * jump_time_to_peak)) * -1.0
@onready var fall_gravity : float = ((-2.0 * jump_height) / (jump_time_to_descent * jump_time_to_descent)) * -1.0

@onready var ray_cast_right = $RayCastRight
@onready var ray_cast_left = $RayCastLeft
@onready var animated_sprite_2d = $AnimatedSprite2D


var wall_stick : bool = false

func _physics_process(delta):
	if ray_cast_right.is_colliding() or ray_cast_left.is_colliding():
		if velocity.y < 0:
			velocity.y = 0
		if Input.is_action_just_pressed("Touch") and not is_on_floor():
			if ray_cast_left.is_colliding() or ray_cast_right.is_colliding():
				direction *= -1
				jump()
	if is_on_floor():
		animated_sprite_2d.play("Moving")
	if velocity.y < 0:
		animated_sprite_2d.play("Jumping")
	if velocity.y > 0:
		animated_sprite_2d.play("Falling")
		if is_on_wall():
			animated_sprite_2d.play("WallSlide")

	
	if direction < 0:
		animated_sprite_2d.flip_h = true
	if direction > 0:
		animated_sprite_2d.flip_h = false
	
	if ray_cast_right.is_colliding() and is_on_floor():
		direction = -1
		
	if ray_cast_left.is_colliding() and is_on_floor():
		direction = 1
	
	position.x += Speed * direction * delta 

	if not is_on_floor():
		if (ray_cast_left.is_colliding() or ray_cast_right.is_colliding()):
			velocity.y += get_gravity() * 0.2 * delta
		elif (ray_cast_left.is_colliding() or ray_cast_right.is_colliding()) and velocity.y > 0:
			velocity.y += get_gravity() * 0.3 * delta
		else: 
			velocity.y += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("Touch") and is_on_floor():
		jump()
	
	move_and_slide()


func get_gravity() -> float:
	return jump_gravity if velocity.y < 0.0 else fall_gravity

func jump():
	animated_sprite_2d.play("Takeoff")
	velocity.y = jump_velocity

Issue #1
Connect the “animation_finished” signal to your script:

func _ready():
    animated_sprite_2d.animation_finished.connect(_on_animation_finished)

func _on_animation_finished():
    if animated_sprite_2d.animation == "Takeoff":
        # put your takeoff-logic here, e.g.:
        animated_sprite_2d.play("Jumping")
        velocity.y = jump_velocity

and change your jump-method to this:

func jump():
    animated_sprite_2d.play("Takeoff")

for this to work you have to change your physics_process a bit. Remove (or comment them out) these lines for now:

    if is_on_floor():
		animated_sprite_2d.play("Moving")
	if velocity.y < 0:
		animated_sprite_2d.play("Jumping")

Try this first and when this works we can handle the other issues

2 Likes

The take off solution worked.
2024-08-1019-54-44-ezgif.com-video-to-gif-converter
Any idea what to do with the moving animation?

Disclaimer: What you are missing in your original code is a “State-Machine”. There are a lot of tutorials on them on youtube and they are a core building block of most games. For future projects it can be helpful to look those up.

For the moving animation:
go to your physics-process and put this where you uncommented/deleted the if’s from before:

if is_on_floor() and animated_sprite_2d.animation != "Takeoff":
		animated_sprite_2d.play("Moving")
1 Like

Thanks for the advice. I’m just creating the game while learning so I’m preety new to this stuff.
Issue 1 is completely solved. Thank you

In your last gif it looks like the wallslide animation is playing. is issue #2 also resolved?

EDIT: Ah i think i see the problem.

if velocity.y > 0:
	animated_sprite_2d.play("Falling")
	if is_on_wall() and animated_sprite_2d.animation != "WallSlide":
		animated_sprite_2d.play("WallSlide")
1 Like

It still plays just the first frame, not the whole animation

Okay i think the best way would be to do a state-machine now. Note that this is not a very good state machine, but i tried to stay close to your original code
First create an enum with your states:

enum {MOVING, TAKEOFF, JUMPING, FALLING, WALLSLIDE, LANDING}
var state: int = MOVING

Then change your code to the following:

var in_air = false

func _physics_process(delta):
	if ray_cast_right.is_colliding() or ray_cast_left.is_colliding():
		if velocity.y < 0:
			velocity.y = 0
		if Input.is_action_just_pressed("Touch") and not is_on_floor():
			if ray_cast_left.is_colliding() or ray_cast_right.is_colliding():
				direction *= -1
				jump()

    if is_on_floor:
        if in_air:
            in_air = false
            state = LANDING
            animated_sprite_2d.play("Landing")
	    elif not state in [MOVING, TAKEOFF, LANDING]:
            state = MOVING
		    animated_sprite_2d.play("Moving")
	if velocity.y < 0 and state != JUMPING:
        state = JUMPING
		animated_sprite_2d.play("Jumping")
	if velocity.y > 0 and state != FALLING:
		if is_on_wall():
			animated_sprite_2d.play("WallSlide")
            state = WALLSLIDE
        else:
            state = FALLING
		    animated_sprite_2d.play("Falling")
	

	
	if direction < 0:
		animated_sprite_2d.flip_h = true
	if direction > 0:
		animated_sprite_2d.flip_h = false
	
	if ray_cast_right.is_colliding() and is_on_floor():
		direction = -1
		
	if ray_cast_left.is_colliding() and is_on_floor():
		direction = 1
	
	position.x += Speed * direction * delta 

	if not is_on_floor():
		if (ray_cast_left.is_colliding() or ray_cast_right.is_colliding()):
			velocity.y += get_gravity() * 0.2 * delta
		elif (ray_cast_left.is_colliding() or ray_cast_right.is_colliding()) and velocity.y > 0:
			velocity.y += get_gravity() * 0.3 * delta
		else: 
			velocity.y += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("Touch") and is_on_floor():
		jump()
	
	move_and_slide()


func get_gravity() -> float:
	return jump_gravity if velocity.y < 0.0 else fall_gravity

func jump():
     if state == JUMPING:
        return
    state = TAKEOFF
	animated_sprite_2d.play("Takeoff")

func _on_animation_finished():
    if animated_sprite_2d.animation == "Takeoff":
        # put your takeoff-logic here, e.g.:
        animated_sprite_2d.play("Jumping")
        state = JUMPING
        in_air = true
        velocity.y = jump_velocity
    elif animated_sprite_2d.animation == "Landing":
         animated_sprite_2d.play("Moving")
         state = MOVING
1 Like

The landing animation dosent play, but other than that everything works. Thank you very much

Oh yeah you have to change this:

if is_on_floor and state != TAKEOFF:
        if in_air:
            in_air = false
            state = LANDING
            animated_sprite_2d.play("Landing")
1 Like

That worked. Again Thank you very much for your help and time.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.