I have a weird issue with the TextureProgressBar that I can’t solve.
I’m trying to use a composition workflow for as much of my game as possible, so I have an HP bar that I can attach to my player’s UI in the scene tree, or enemies, objects, etc. It is in turn attached to a HealthComponent node, and get’s the new_health variable from the CurrentHealth of that attached component.
When it’s just one player, or the host, the code and HealthBar run fine. But when I have a player client connect, the TextureProgressBar doesn’t update for them. They can still receive damage, they still die when their health is depleted like they’re supposed to. And I think my debug print statements are getting the proper information about the host and client id since the functionality of the health system works for both players.
It’s even saying that the health bar value is decrementing for the client, even though visually it’s not.
Here’s my code for the HealthBar. I just can’t seem to figure this out. Any idea’s as to what I’m doing wrong?
extends TextureProgressBar
class_name HealthBarComponent
@export var health_component_path: NodePath
@onready var health_component: HealthComponent = get_node_or_null(health_component_path)
var parent_node
var owner_id : int
func _ready():
parent_node = get_parent().get_parent()
owner_id = parent_node.get_multiplayer_authority()
print("parent owner_id ", owner_id)
if health_component:
max_value = health_component.MAX_HEALTH
value = max_value
health_component.health_changed.connect(update_health_bar)
func update_health_bar(new_health: int): #new health is being passed as an int from the health_changed signal
value = new_health
modulate = Color.PURPLE
print("HP Bar value", value, " for owner_id ", owner_id)
if value <= .25 * max_value:
tint_progress = Color.RED
print("turned red at ", value)
When a MultiplayerSynchronizer updates a value it will set the property directly.
Since you have a signal from the health component, you should probably put a setter function on health variable that will emit the signal. To the UI on the client.
@export var health = 100 :
Set(value):
Health = value
Health_changed.emit(health)
If the only value being synchronized is health, you could just leverage the MultiplayerSynchronizer’s synchronized signal to do something similar.
Hey pennyloafers, thank you for the response!
I tried doing that, and I like having the emit happen in the health variable, instead of when the player takes damage, but synchronizing the value now has a similar problem I’ve been struggling with, which is that on receiving damage, both players health bars are decremented at the same time, and I only get the proper decrement when the host player dies. And leaving off the multiplayer synchronization still has only the host updating it’s health bar until it dies, and then the client is able to update it’s health
Here also is the Health Component script:
extends Node3D
class_name HealthComponent
signal health_changed(CurrentHealth) #update health bar by decremented health.
signal isBloodied #graphical change. Blink health bar, change player textures to bloodied
signal hasDied #health reaches 0
signal isAnEnemy
signal isSelf
signal isFriendly
@export var MAX_HEALTH : int
@export var isEnemy = false #is this an enemy
@export var CurrentHealth = 100 :
set(value):
CurrentHealth = value
health_changed.emit(CurrentHealth)
func _ready():
CurrentHealth = MAX_HEALTH
@rpc("any_peer")
func damage(attack: Attack): #attack is just a variable holder class
CurrentHealth = max(CurrentHealth - attack.Enemy_Attack_Damage, 0.0)
if CurrentHealth <= 0:
CurrentHealth = 0
emit_signal("hasDied")
get_parent().queue_free()