Health Bar / TextureProgressBar not updating or show anything when player get a hit from enemy in gameplay

Godot 4,3

Question

I have one problem when the enemy shoot me nothing happens to the Health Bar for the player it's still the same not updating or changing, then the player dies after 30 hits from the enemy

health bar script

extends TextureProgressBar


@export var character: CharacterBody2D

@onready var health: Health = character.get_node("Health")
@onready var health: Health = character.find_children("*", "Health")[0]


func _ready() -> void:
	max_value = health.max_health
	value = health.health
	health.health_changed.connect(_update_bar)


func _update_bar(_diff: int) -> void:
	value = health.get_health()

Hi!

Have you made sure the _update_bar function is called correctly? If not, the signal health_changed may not be called correctly.

If yes, have you then made sure that health.get_health() returns a value going from 30 to 0? If not, the health value itself is wrong (although it would be weird since you said the player dies correctly after 30 hits).

1 Like

in my player script the max health is 30

extends CharacterBody2D

var health = 30

now when I change the value like this and save the scene
it will be like this in game

but when I get a hit from the enemy 10 or 30 times nothing happens to the health bar !
the player just dies after 30 hit

what did I mess this time? lol

As I asked, Have you made sure the _update_bar function is called correctly? Add a print inside of it and see if it shows in the console when the players gets hit.

2 Likes

like this?

func _update_bar(_diff: int) -> void:
	value = health.get_health()
	print(_update_bar)

I did it like this then I entered the game and got hits from the enemy, but nothing has been shown in the Output after adding the print()
no message, nothing.

If there’s no message, that means the function is not called at all, which is why your progress bar doesn’t change (while the player health changes correctly).

Now, what you can check is the signal the function is connected to:
health.health_changed.connect(_update_bar). Since you’re doing that in _ready, I guess the connection is done (but I’d suggest you also add a print there to make sure of that).
Next thing to check is that the signal is emitted correctly, by using health_changed.emit in the health script. And again, if you’re emitting it already, add a print right before the signal emission to ensure it’s called properly.

1 Like

when i did this

func _ready() -> void:
	max_value = health.max_health
	value = health.health
	health.health_changed.connect(_update_bar)
	print(health.health_changed.connect(_update_bar))

I got a message 31

Yes, as suspected, the signal is correctly being connected too, but what about the signal emission?
You’re connecting to a signal, but you need to emit it, otherwise, the connexion to it is pointless.

1 Like

okay thanks for trying to help me solve these issues

but what exactly should I do here
this is the health script

class_name Health
extends Node


signal max_health_changed(diff: int)
signal health_changed(diff: int)
signal health_depleted


@export var max_health: int = 31 : set = set_max_health, get = get_max_health
@export var immortality: bool = false : set = set_immortality, get = get_immortality

var immortality_timer: Timer = null

@onready var health: int = max_health : set = set_health, get = get_health


func set_max_health(value: int):
	var clamped_value = 1 if value <= 0 else value
	
	if not clamped_value == max_health:
		var difference = clamped_value - max_health
		max_health = value
		max_health_changed.emit(difference)
		
		if health > max_health:
			health = max_health


func get_max_health() -> int:
	return max_health


func set_immortality(value: bool):
	immortality = value


func get_immortality() -> bool:
	return immortality


func set_temporary_immortality(time: float):
	if immortality_timer == null:
		immortality_timer = Timer.new()
		immortality_timer.one_shot = true
		add_child(immortality_timer)
	
	if immortality_timer.timeout.is_connected(set_immortality):
		immortality_timer.timeout.disconnect(set_immortality)
	
	immortality_timer.set_wait_time(time)
	immortality_timer.timeout.connect(set_immortality.bind(false))
	immortality = true
	immortality_timer.start()


func set_health(value: int):
	if value < health and immortality:
		return
	
	var clamped_value = clampi(value, 0, max_health)
	
	if clamped_value != health:
		var difference = clamped_value - health
		health = value
		health_changed.emit(difference)
		
		if health == 0:
			health_depleted.emit()
			

func get_health():
	return health

Well… I’ve said it multiple times already :sweat_smile: check if the signal is being emitted.

You have sometimes that doesn’t work, so you want to start from the line of code that’s not working, and go up in the trace, step by step, until you find the issue, so:
1/ Health bar not refreshing → check if _update_bar is called.
2/ _update_bar is not called → check if it’s correctly connected to the health_changed signal.
3/ It is connected → check if the signal is emitted.
4/ and so on until you find the issue.

So you need to do something like this:

if clamped_value != health:
    var difference = clamped_value - health
    health = value
    health_changed.emit(difference)
    print(difference)

If the print(difference) is showing in console, that means the signal is called too (since it’s just above), which means the issue is somewhere else.
If the print is not showing, that means the signal is not called either, and that’s your issue.

When debugging, you want to first identify the problem, and then find a fix. Most of the time, finding the issue is 90% of the work, so do it properly, step by step, read your code slowly and add lots of print to have a good understanding of what’s going on, in what order, etc.

2 Likes

@Ahmed1, @sixrobin means that you need to show us the script that has the emit() function that links to the signal you connected with your node

Hope my layman terms work out :sweat_smile:

1 Like

well, the print here is not showing anything too lol
forgive me I am very new to all of this, and English is not my first language
so how to call it if it’s not called, what i must change i am getting too old for this…
$

	if clamped_value != health:
		var difference = clamped_value - health
		health = value
		health_changed.emit(difference)
		print(difference)

Once again, you need to go one step up in your code : you have a print instruction that is not called. Why is that?

Multiple possibilities:
1/ Since it is inside an if block, maybe it has something to do with the condition. In other words, maybe the if clamped_value != health condition has something not working.
2/ Since it is inside the set_health(value: int) function, maybe that function is not called at all.
3/ More tricky but a thing to check: the function has an “early return” condition (if value < health and immortality: return). If that condition has something not working properly, it may return when not intended, hence not calling the rest of the function.

You need to read your code slowly, step by step, add prints, and at some point you will see something weird going on, and you’ll have to fix it.
Also, I’d suggest you take a break and come back to this later on; debugging is much easier after a break and doing something else.

1 Like

I have solved the problem thanks, now when the player gets a hit from the enemy bullet I can see the health bar changing - updating then the player dies after many hits

2 Likes