Best way to detect players health

Currently I’m doing this

local function updateHealth(health)
	HealthBar.Bar:TweenSize(UDim2.new(health / Humanoid.MaxHealth, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
	HealthBar.Health.Text = health
end

Humanoid.HealthChanged:Connect(updateHealth)

Which is fine, however, when a player dies, and respawns, the UI stays at saying their health is 0. The UI.ResetOnSpawn is set to false. I CAN NOT change this, due to other sections in the UI’s code. This property has to remain.

So is there any other way I can detect a players health, without resorting to while loops or using RunService to constantly check

4 Likes

Can you not just do this every time the humanoid is loaded in?

1 Like

There are two methods; Connect it to a character added event:

local function updateHealth(health)
	HealthBar.Bar:TweenSize(UDim2.new(health / 100, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
	HealthBar.Health.Text = health
end
game.Players.LocalPlayer.CharacterAdded:Connect(function(char)--Every time there is a new character, bind the event 
   char:WaitForChild('Humanoid').HealthChanged:Connect(updateHealth)
end)

Or update the health every frame:

local function updateHealth(health)
	HealthBar.Bar:TweenSize(UDim2.new(health / 100, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
	HealthBar.Health.Text = health
end
game:GetService('RunService').RenderStepped:Connect(function()
    local plr = game.Players.LocalPlayer
    if plr.Character then       
       updateHealth(plr.Character:WaitForChild('Humanoid').Health)
    end
end)

Disclaimer: This was typed on mobile so I apologize for any typos or autocorrects that may have occured. Thank you.

3 Likes

This is not the question asked, he can already detect health changes. He needs to detect when the player respawns.

1 Like

Ahh, thanks. I wasn’t really positive on what he was asking.

1 Like

Create a seperate gui?
You shouldn’t need to put everything under one screen gui.
If you did still want to keep it under one screen gui then you could just change the humanoid variable, disconnect the previous health changed event, and create a new HealthChanged event for the new humanoid every time CharacterAdded fires.

Why would you make a sperate gui? You could still reuse the old one. Also, this would not help solve the problem but would make it worse.

Also, just side note but connections connected to a nil object will disconnect via garbage collection (very few exceptions, this example should be fine)

How so?

It’s a fairly simple solution, I don’t see why not to.

The question asked was “How do I detect the new humanoid’s health”. Adding Guis has NOTHING to do with the question. That is what I meant by “this would not help the problem”.

As mentioned in the OP, he can’t set ResetOnSpawn to true because of other things in the same GUI, so if he made another gui then he could set ResetOnSpawn to true for that specific gui with the health bar which should fix the issue.

game:GetService('RunService').RenderStepped:Connect(function()
	print(Humanoid.Health)
	local RoundedHealth = math.floor(Humanoid.Health + 0.5) -- So it doesn't display like 50,53262626737
	HealthBar.Bar:TweenSize(UDim2.new(RoundedHealth / Humanoid.MaxHealth, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
	HealthBar.Health.Text = RoundedHealth 
end)

The print prints 100, then when I die 0, but then when I respawn it keeps printing 0

That’s because you’re not redefining the humanoid when the character is added. Your humanoid variable is stuck to the old one.

How can I easily reapply it then??

game:GetService('RunService').RenderStepped:Connect(function()
    local Character = Player.Character or Player.CharacterAdded:Wait()
    local Humanoid = Character:WaitForChild('Humanoid')
	local Health = math.floor(Humanoid.Health + 0.5)
	HealthBar.Bar:TweenSize(UDim2.new(Health / Humanoid.MaxHealth, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
	HealthBar.Health.Text = Health
end)

Doesn’t seem like the most efficient way to do this??

That would be pretty inefficient since you’ll have a large number of yielding functions waiting on a character being added at certain points considering the function is being called with render stepped.
It would be much better to instead have a connection for when the character is added and then connect the health changed to the new humanoid. This is how I would do it:

local Humanoid
local function updateHealth(health)
	HealthBar.Bar:TweenSize(UDim2.new(health / Humanoid.MaxHealth, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
	HealthBar.Health.Text = health
end
function NewCharacter(c)
    Humanoid = c:WaitForChild("Humanoid")
    Humanoid.HealthChanged:Connect(updateHealth)
end
Player.CharacterAdded:Connect(NewCharacter)
-- in hindsight its possible the character may already exist in which case you would call the function on the current character
if Player.Character then
      NewCharacter(Player.Character)
end

The other option would be to just not tween it while the player doesn’t have a character and if the player does have a character, tween the health, dynamically using the player’s current character and humanoid in the render stepped function. Whatever you do just don’t yield the renderstepped function for an event.

Edit: That is what RealTimothy0812 was suggesting, you were just implementing incorrectly.

3 Likes

Now it doesn’t display it when the player joins, and still doesn’t change when the player dies, it stays at 0

Have you tried this way to detect a players health, it seems to work perfect for me:

local player = game.Players.LocalPlayer
local healthBar = script.Parent:WaitForChild("HealthBar")
local hum = player.Character:WaitForChild("Humanoid")

player.Character:WaitForChild("Humanoid").Changed:Connect(function(Type)
	if Type == "Health" then
		healthBar.ProgressBar:TweenSize(UDim2.new(hum.Health / hum.MaxHealth, 0, 1, 0), "Out", "Linear", 0.25, true)
		healthBar.HealthText.Text = tostring(math.floor(hum.Health) .. "/" .. math.floor(hum.MaxHealth))
	end
end)

When the character respawns i just subtract the health by 1 and it regens right back and it fires the updateHealth function making the bar full again

local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:wait()
plr.CharacterAdded:Connect(function()
     plr.Character:WaitForChild("Humanoid").HealthChanged:Connect(updateHealth)
     plr.Character.Humanoid.Health = plr.Character.Humanoid.Health - 1
end)
char.Humanoid.HealthChanged:Connect(updateHealth)
1 Like

That won’t work for OP’s use case because they’re putting it inside a LayerCollector with RespawnOnSpawn as false. This will just try to reference the character’s old character and humanoid for as long as the script is present.

My opinion, the way that pops up in my head is to create a module script in ReplicatedFirst/Storage and then requiring it in the GUI to update the players health

1 Like

I do this by forcefully activating the tween at the start of the script,so it runs everytime the player respawns.Like this.

HealthBar.Bar:TweenSize(UDim2.new(health / Humanoid.MaxHealth, 0, 1, 0),  Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
HealthBar.Health.Text = health
--tween as the script reads for the first time(when the player respawns).
local function updateHealth(health)
HealthBar.Bar:TweenSize(UDim2.new(health / Humanoid.MaxHealth, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.25, true)
HealthBar.Health.Text = health
end

Humanoid.HealthChanged:Connect(updateHealth)
--The rest of your script.

Unless your script doesn’t reset upon death,this should work.

2 Likes