TextureProgressBar value not updating on client

Godot Version

Godot 4.2.1

Question

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?

image

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.

2 Likes

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()

what is probably happening is that when two players are spawned their UI’s overlay on eachother.

To solve this we need to hide/remove the ui for the remote players.

1 Like

Oh my gosh, that was the problem!
Fixed with one new function and a ready call:

@rpc("call_remote")
func hide_remote_ui():
	if multiplayer.multiplayer_peer and multiplayer.get_unique_id() != owner_id:
		health_bar.hide()

Thank you, I didn’t even think about that :smiley:

1 Like

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