Player dont die either plays death animation

Hello everyone im having some trouble to make the player gets dead. After reaches 0 health points he still alive and dont play animation for death. any idea what is missing?

extends CharacterBody2D

var speed = 100
var player_state
var health = Player_data.player_health

@export var inv: Inv

var gun_equiped = false
var gun_cooldown = true
var bullet = preload(“res://Scenes/bullet.tscn”)
var mouse_loc_from_player = null
var is_dead = false

func _ready():
$CollisionShape2D.disabled = false
$hitbox/CollisionShape2D.disabled = false
print(health)

func _physics_process(_delta):
if is_dead:
return

mouse_loc_from_player = get_global_mouse_position() - self.position

var direction = Input.get_vector("left", "right", "up", "down")

if direction.x == 0 and direction.y == 0:
	player_state = "idle"
elif direction.x != 0 or direction.y != 0:
	player_state = "walking"

velocity = direction * speed
move_and_slide()

if Input.is_action_just_pressed("1"):
	gun_equiped = !gun_equiped

var mouse_pos = get_global_mouse_position()
$Marker2D.look_at(mouse_pos)

if Input.is_action_just_pressed("left_mouse") and gun_equiped and gun_cooldown:
	gun_cooldown = false
	var bullet_instance = bullet.instantiate()
	bullet_instance.rotation = $Marker2D.rotation
	bullet_instance.global_position = $Marker2D.global_position
	add_child(bullet_instance)

	await get_tree().create_timer(1.5).timeout
	gun_cooldown = true

play_anim(direction)

func play_anim(dir):
if player_state == “dead”:
$AnimatedSprite2D.play(“Dying”)
return

if !gun_equiped:
	if player_state == "idle":
		$AnimatedSprite2D.play("Idle")
	elif player_state == "walking":
		if dir.x == 1:
			$AnimatedSprite2D.flip_h = false
		elif dir.x == -1:
			$AnimatedSprite2D.flip_h = true
		$AnimatedSprite2D.play("Walking")
else:
	if player_state == "idle":
		$AnimatedSprite2D.play("Idle_Armed")
	elif player_state == "walking":
		if dir.x == 1:
			$AnimatedSprite2D.flip_h = false
		elif dir.x == -1:
			$AnimatedSprite2D.flip_h = true
		$AnimatedSprite2D.play("Walking_Armed")

# Rotate sprite based on mouse position (if gun equipped)
if gun_equiped:
	if mouse_loc_from_player.x > 0:
		$AnimatedSprite2D.flip_h = false
	else:
		$AnimatedSprite2D.flip_h = true

func player():
pass # Placeholder for character-specific functionality

func collect(item):
inv.insert(item) # Assuming inv is an inventory object

func flash():
$Sprite2D.material.set_shader_parameter(“flash_modifier”, 1)
await get_tree().create_timer(0.3).timeout
$Sprite2D.material.set_shader_parameter(“flash_modifier”, 0)

func dead():
print(“Player is dead”) # Debugging line
is_dead = true
player_state = “dead”
$AnimatedSprite2D.play(“Dying”)
$CollisionShape2D.disabled = true
$hitbox/CollisionShape2D.disabled = true
velocity = Vector2.ZERO # Stop movement
set_process(false) # Stop processing
set_physics_process(false) # Stop physics processing
# Optionally:
# - Play death sound effect
# - Trigger respawn logic
# - Display game over screen

func _on_hitbox_area_entered(area):
if area.is_in_group(“hazard”):
health -= 1 # Adjust damage amount as needed
flash()
print("Health: ", health) # Debugging line
if health <= 0 and not is_dead:
dead()

I took a close look through this; although it’s certainly possible I missed something, I don’t see an obvious reason why dead() would not be getting called.

Because of the debugging print statements you have in place, my assumptions about the results of your control flow testing up to this point are as follows:

  • health is being set correctly in the variable declaration (ie you’re not having any issues pulling from Player_data)
  • health is being decremented correctly when the player enters a “hazard” area
  • you are not seeing “Player is dead”

If these assumptions are not correct, that’s important to know. These assumptions suggest there is something wrong with your conditional statement if health <= 0 and not is_dead:, and if the first two assumptions are correct, the first condition will be true when the player has entered enough hazard areas. This leaves only the and and not is_dead:, the latter of which should also evaluate to true because you set it to false in the variable definition and its value only changes in dead().

The first thing I would do in this case is add more print statements before the conditional, for a total of 3:

print("Health: ", health)
print("is dead: ", is_dead)
print("and result:",  health <= 0 and not is_dead)

In my own test sandbox, this produces the expected result (the and conditional returns true), so in your own project, there is probably something else at play here and I would expect that these tests will hint at it. Breakpoints might help you as well, since you will then be able to see the instantaneous values of the relevant variables. I think you would need to post a link to your project before I could help further than this, so hopefully this test gives you another thread to pull on before that’s necessary. Good luck!

1 Like

I have sent the link via DM. ty for the help!

1 Like

Project opened, and I think I see the problem already.

When I run the project using World.tscn as the project’s main scene (it was set to Player for some reason), the first thing I see is a hungry jaguar barrelling toward me! Nicely done!

What I don’t see is any of the print statements that were added to the player script - and I can see that you did add them. Sure enough, this means that the assumptions I talked about are not so ironclad after all, which makes sense. It turns out that the issue is something I’ve seen before in a 3D project.

Onca is added to the hazard group, but when onca and player collide, the onca root node is not what is being checked. By writing print(area) immediately under player’s func _on_hitbox_area_entered(area): function declaration, what returns is onca’s various Area2Ds, and not the CharacterBody2D root node. For this to work properly, you need to do one or the other of these 2 things:

  1. choose which onca Area2D you want to use for damaging the player and add that Area2D to the hazard group. My guess would be “atk_area”.
  2. change if area.is_in_group("hazard"): to if area.owner.is_in_group("hazard"):, which will point to the onca root node (the CharacterBody2D)

Personally, I would rather use option 2, but this would require you to change the fact that you have dedicated Area2Ds for different purposes; it would cause ALL of them to damage the player individually, since the player is not distinguishing between these areas.

Because of this, I implemented option 1 and it seems to work (although the collision detection is a bit unreliable). There are some new problems I noticed:

  • flash() raises an error because player.Sprite2D doesn’t exist. You will probably be able to fix this very easily.
  • Disabling the player’s CollisionShapes should not be done directly (something I was not even thinking about!) because this needs to be done in-between physics frames using call_deferred(). Here’s how I fixed that:
    cap
  • the heart meter does not always reduce correctly from 1 heart to 0 when the player dies. I did notice that there was a significant delay between taking damage (debug messages) and this heart meter actually updating, so you probably just need to simplify how the heart meter gets its data. I didn’t look into that.

Neat stuff! You had the right idea using print statements to do your testing. In the future, just use even more and try to break down every single step the code makes. Have fun with the project!

1 Like

Hey BH67! Thank you very much for guiding me! I’ve been trying to fix this for weeks haha, I’ll try to apply the changes you posted here! thank you again!

1 Like

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

Privacy & Terms