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:
What happens in game:
###ISSUE 2:
The wall slide animation dosent play.
Animation:
What happens In game:
###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:
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
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")
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")
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