Character floating when they jump before dies

Godot Version

4.4.1

Question

I’m having a problem where when the player dies while falling, they stays floating in the air instead of falling to the ground.

Here’s the player’s code:

extends CharacterBody2D

func _ready() -> void:
	add_to_group("player")

const SPEED = 130.0
const JUMP_VELOCITY = -300.0

@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

var is_alive: bool = true

func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("jump") and is_on_floor() and is_alive:
		velocity.y = JUMP_VELOCITY
	
	if is_alive:
		var direction := Input.get_axis("move_left", "move_right")
		
		# Flip the character
		if direction > 0:
			animated_sprite.flip_h=false
		elif direction < 0:
			animated_sprite.flip_h=true
		
		# play the animations
		if is_on_floor():
			if direction==0:
				animated_sprite.play("idle")
			else:
				animated_sprite.play("run")
		else:
			animated_sprite.play("jump")
		
		if direction:
			velocity.x = direction * SPEED
		else:
			velocity.x = move_toward(velocity.x, 0, SPEED)

		move_and_slide()

# Dying >:3
func die():
	is_alive = false
	$AnimatedSprite2D.play("death")

And here is a video of someone who had the same problem: https://imgur.com/a/mBavfAr

As soon as you set is_alive = false, everything underneath that stops running - that includes all your physics movement calculations. Just un-indent everything after you get the input, as that’s the only thing you want to stop doing when the character dies.

extends CharacterBody2D

func _ready() -> void:
	add_to_group("player")

const SPEED = 130.0
const JUMP_VELOCITY = -300.0

@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

var is_alive: bool = true

func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("jump") and is_on_floor() and is_alive:
		velocity.y = JUMP_VELOCITY
	
	if is_alive:
		var direction := Input.get_axis("move_left", "move_right")
		
	# Flip the character
	if direction > 0:
		animated_sprite.flip_h=false
	elif direction < 0:
		animated_sprite.flip_h=true
	
	# play the animations
	if is_on_floor():
		if direction==0:
			animated_sprite.play("idle")
		else:
			animated_sprite.play("run")
	else:
		animated_sprite.play("jump")
		
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()

# Dying >:3
func die():
	is_alive = false
	$AnimatedSprite2D.play("death")
1 Like

Thank You for responding, but now this error occurs:

(sorry, i’m new to this codding stuff)

Your variable “direction” can be used only inside the scope of the if statement where you now declare it.
Declare it so that it can be used script wide by adding it somewhere at the top, outside of any function, and then remove “var” from where you have put “var” now.
If you e.g. declare a variable in a script, it can only be used in that script. If in a function, only in that function. In an if statement, only in that if statement. And so forth. So you should declare it from somewhere all the things that needs it can access it and then when you need to change it, change it from elsewhere - but don’t create it elsewhere.

2 Likes

something like this? but with that, the character no longer play the death animation

extends CharacterBody2D

func _ready() -> void:
	add_to_group("player")

const SPEED = 120.0
const JUMP_VELOCITY = -290.0

@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

var direction
var is_alive: bool = true

func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("jump") and is_on_floor() and is_alive:
		velocity.y = JUMP_VELOCITY
	
	if is_alive:
		direction = Input.get_axis("move_left", "move_right")
		
	# Flip the character
	if direction > 0:
		animated_sprite.flip_h=false
	elif direction < 0:
		animated_sprite.flip_h=true
	
	# play the animations
	if is_on_floor():
		if direction==0:
			animated_sprite.play("idle")
		else:
			animated_sprite.play("run")
	else:
		animated_sprite.play("jump")
		
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()

# Dying >:3
func die():
	is_alive = false
	$AnimatedSprite2D.play("death")

Here’s a video showing what’s happening: https://youtu.be/fYRkMFLre0I

Re-indent the part under your # play animation comment

1 Like

The main problem has been solved, but now another one has arisen that… I don’t even know how to explain, so I recorded a video showing it

The problem is caused because the player’s movement direction is not updated when they die.

Imagine:

In the first frame, the movement direction is queried according to the player’s input.

The value is determined to be 1.

In the second frame, the player is dead. The direction of movement is not updated to 0, so it remains 1.

Result: The player slides even in death.

2 Likes

I finally fixed all the bugs in the game. I used the animation node to make the death animation work properly. I’m not proud of the code I wrote because I know I could have optimized it more, but for a first project, I think it’s fine, and as they say, “if it works, it works.” Anyway, thank you very much for helping me understand what was wrong with the code ^^. I’ll leave the final version here for anyone who wants to take a look or just feel disgusted (which I think is more likely xD)


extends CharacterBody2D

func _ready() -> void:
	add_to_group("player")

const SPEED = 130.0
const JUMP_VELOCITY = -295.0

@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D
@onready var animation_player: AnimationPlayer = $AnimationPlayer
@onready var timer: Timer = $Timer
@onready var hit_sound: AudioStreamPlayer2D = $sfx

var direction
var is_alive: bool = true

func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("jump") and is_on_floor() and is_alive:
		velocity.y = JUMP_VELOCITY
	
	if is_alive:
		direction = Input.get_axis("move_left", "move_right")
		
	# Flip the character
	if direction > 0 and is_on_floor() and is_alive:
		animated_sprite.play("run")
		animated_sprite.flip_h=false
	elif direction < 0 and is_on_floor() and is_alive:
		animated_sprite.play("run")
		animated_sprite.flip_h=true
	elif direction == 0 and is_on_floor() and is_alive:
		animated_sprite.play("idle")
	elif direction > 0 and !is_on_floor() and is_alive:
		animated_sprite.play("jump")
		animated_sprite.flip_h=false
	elif direction < 0 and !is_on_floor() and is_alive:
		animated_sprite.play("jump")
		animated_sprite.flip_h=true
	elif direction == 0 and !is_on_floor()and is_alive:
		animated_sprite.play("jump")
	
	# play the animations (old system that i couldn't get to work)
		#if is_on_floor():
			#if direction==0:
				#animated_sprite.play("idle")
			#else:
				#animated_sprite.play("run")
		#else:
			#animated_sprite.play("jump")
		
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()

# Dying >:3
func die():
	is_alive = false
	direction = 0
	animation_player.play("death")

func death_animation():
	som.play()
	animated_sprite.play("death")
	Engine.time_scale = 0.5
	timer.start()

func _on_timer_timeout() -> void:
	Engine.time_scale = 1.0
	get_tree().reload_current_scene()

(i will problably try make it shorter later, but for now, i think it’s “good”)

1 Like