GUI cloning into PlayerGui only once

I have this armour bar GUI that is cloned from ReplicatedStorage and gets put into a ScreenGui in the PlayerGui. Problem is this only works once and if the player dies or resets, it doesn’t clone again. What could be the reason?

local armourBar = game:GetService("ReplicatedStorage"):WaitForChild("armourBar")
local armourMax = 50

function updateGui(gui, armourAmount)
	local y = armourAmount / armourMax
	gui:WaitForChild("container"):WaitForChild("bar").Size = UDim2.new(y, 0, 1, 0)
end

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		local humanoid = character:WaitForChild("Humanoid")
		local newGui = armourBar:Clone()
		newGui.Parent = player:WaitForChild("PlayerGui"):WaitForChild("MainScreenGui"):WaitForChild("playerBars")
		
		local armour = armourMax
		local oldHealth = humanoid.Health
		
		updateGui(newGui, armour)
		
		humanoid.HealthChanged:Connect(function(newHealth)
			if armour > 0 and newHealth < oldHealth then
				local change = oldHealth - newHealth
				
				humanoid.Health = humanoid.MaxHealth
				armour = armour - change
				
				local healthMinus = math.clamp(armour, -humanoid.MaxHealth, 0)
				updateGui(newGui, math.clamp(armour, 0, armourMax))
				
				oldHealth = humanoid.MaxHealth + healthMinus
				humanoid.Health = oldHealth
			end
		end)
	end)
end)
5 Likes

Maybe use return ?

local armourBar = game:GetService("ReplicatedStorage"):WaitForChild("armourBar")
local armourMax = 50

function updateGui(gui, armourAmount)
	local y = armourAmount / armourMax
	gui:WaitForChild("container"):WaitForChild("bar").Size = UDim2.new(y, 0, 1, 0)
end

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		local humanoid = character:WaitForChild("Humanoid")
		local newGui = armourBar:Clone()
		newGui.Parent = player:WaitForChild("PlayerGui"):WaitForChild("MainScreenGui"):WaitForChild("playerBars")
		
		local armour = armourMax
		local oldHealth = humanoid.Health
		
		updateGui(newGui, armour)
		
		humanoid.HealthChanged:Connect(function(newHealth)
			if armour > 0 and newHealth < oldHealth then
				local change = oldHealth - newHealth
				
				humanoid.Health = humanoid.MaxHealth
				armour = armour - change
				
				local healthMinus = math.clamp(armour, -humanoid.MaxHealth, 0)
				updateGui(newGui, math.clamp(armour, 0, armourMax))
				
				oldHealth = humanoid.MaxHealth + healthMinus
				humanoid.Health = oldHealth
			end
		end)

        humanoid.Died:Connect(function()
             return
        end)
	end)
end)
2 Likes

Just tried it and nope. No luck.

2 Likes

Maybe try to wait the RespawnTime and then return the whole script?

wait(game.Players.RespawnTime)
return
2 Likes

“Problem is this only works once and if the player dies or resets, it doesn’t clone again.”

That’s the issue, the UI is cloned and is managed by the server so ResetOnSpawn cannot do anything. Return has to be the solution.

1 Like

I just commented straight up after reading the title. Sorry for that.

Try changing game.Players.PlayerAdded:Connect(function(player) end) for

for _, Player in ipairs (game:GetService('Players'):GetPlayers()) do
    -- the rest of your code; unchanged.
end
1 Like

Like this?

local armourBar = game:GetService("ReplicatedStorage"):WaitForChild("armourBar")
local armourMax = 50

function updateGui(gui, armourAmount)
	local y = armourAmount / armourMax
	gui:WaitForChild("container"):WaitForChild("bar").Size = UDim2.new(y, 0, 1, 0)
end

for _, Player in ipairs (game:GetService("Players"):GetPlayers()) do
	Player.CharacterAdded:Connect(function(character)
		local humanoid = character:WaitForChild("Humanoid")
		local newGui = armourBar:Clone()
		newGui.Parent = Player:WaitForChild("PlayerGui"):WaitForChild("MainScreenGui"):WaitForChild("playerBars")

		local armour = armourMax
		local oldHealth = humanoid.Health

		updateGui(newGui, armour)

		humanoid.HealthChanged:Connect(function(newHealth)
			if armour > 0 and newHealth < oldHealth then
				local change = oldHealth - newHealth

				humanoid.Health = humanoid.MaxHealth
				armour = armour - change

				local healthMinus = math.clamp(armour, -humanoid.MaxHealth, 0)
				updateGui(newGui, math.clamp(armour, 0, armourMax))

				oldHealth = humanoid.MaxHealth + healthMinus
				humanoid.Health = oldHealth
			end
		end)
	end)
end

Now it doesn’t show up at all.

1 Like

In addition to this, you’re only listening to the character being added once. What you need to do is ensure if the character already exists, and then run the callback on that character. Also add a listener for CharacterAdded and that will run if the character didnt exist yet. I provided a code snippet below on how to properly handle PlayerAdded & CharacterAdded

local Players = game:GetService("Players")

-- Player added:
local function playerAdded(player)

    -- character added callback
    local function characterAdded(character)
        -- do the UI clone here
    end

    if player.Character then
        -- will run if character already exists
        characterAdded(player.Character)
    end

    -- runs when character is added
    player.CharacterAdded:Connect(characterAdded)
end

-- The for loop gets players in game who were added before the player added listener could connect
for _, player in ipairs(Players:GetPlayers()) do
    playerAdded(player)
end

-- Each time a new player is added after for loop
Players.PlayerAdded:Connect(playerAdded)
1 Like
local Players = game:GetService("Players")

local armourBar = game:GetService("ReplicatedStorage"):WaitForChild("armourBar")
local armourMax = 50

function updateGui(gui, armourAmount)
	local y = armourAmount / armourMax
	gui:WaitForChild("container"):WaitForChild("bar").Size = UDim2.new(y, 0, 1, 0)
end

-- Player added:
local function playerAdded(player)

	-- character added callback
	local function characterAdded(character)
		local humanoid = character:WaitForChild("Humanoid")
		local newGui = armourBar:Clone()
		newGui.Parent = player:WaitForChild("PlayerGui"):WaitForChild("MainScreenGui"):WaitForChild("playerBars")

		local armour = armourMax
		local oldHealth = humanoid.Health

		updateGui(newGui, armour)

		humanoid.HealthChanged:Connect(function(newHealth)
			if armour > 0 and newHealth < oldHealth then
				local change = oldHealth - newHealth

				humanoid.Health = humanoid.MaxHealth
				armour = armour - change

				local healthMinus = math.clamp(armour, -humanoid.MaxHealth, 0)
				updateGui(newGui, math.clamp(armour, 0, armourMax))

				oldHealth = humanoid.MaxHealth + healthMinus
				humanoid.Health = oldHealth
			end
		end)
	end

	if player.Character then
		-- will run if character already exists
		characterAdded(player.Character)
	end

	-- runs when character is added
	player.CharacterAdded:Connect(characterAdded)
end

-- The for loop gets players in game who were added before the player added listener could connect
for _, player in ipairs(Players:GetPlayers()) do
	playerAdded(player)
end

-- Each time a new player is added after for loop
Players.PlayerAdded:Connect(playerAdded)

It still doesn’t come back after the player dies. Could this be because this script is in ServerScriptService?

Try setting the ResetOnSpawn property for the MainScreen gui to false, and see what happens. It might be resetting when the player dies. Also are there any errors/warning in the output console when they respawn?

1 Like

I added a for loop before the variables as when the player reset the armor bar wouldn’t get rid of the old one but now the health bar isn’t updating either.

local Players = game:GetService("Players")

local armourBar = game:GetService("ReplicatedStorage"):WaitForChild("armourBar")
local armourMax = 50

function updateGui(gui, armourAmount)
	local y = armourAmount / armourMax
	gui:WaitForChild("container"):WaitForChild("bar").Size = UDim2.new(y, 0, 1, 0)
end

-- Player added:
local function playerAdded(player)

	-- character added callback
	local function characterAdded(character)
		
		for _, v in ipairs(player:WaitForChild("PlayerGui"):WaitForChild("MainScreenGui"):WaitForChild("playerBars"):GetChildren()) do
			if v.Name == "armourBar" then
				v:Destroy()
			end
		end
		
		local humanoid = character:WaitForChild("Humanoid")
		local newGui = armourBar:Clone()
		newGui.Parent = player:WaitForChild("PlayerGui"):WaitForChild("MainScreenGui"):WaitForChild("playerBars")

		local armour = armourMax
		local oldHealth = humanoid.Health

		updateGui(newGui, armour)

		humanoid.HealthChanged:Connect(function(newHealth)
			if armour > 0 and newHealth < oldHealth then
				local change = oldHealth - newHealth

				humanoid.Health = humanoid.MaxHealth
				armour = armour - change

				local healthMinus = math.clamp(armour, -humanoid.MaxHealth, 0)
				updateGui(newGui, math.clamp(armour, 0, armourMax))

				oldHealth = humanoid.MaxHealth + healthMinus
				humanoid.Health = oldHealth
			end
		end)
	end

	if player.Character then
		-- will run if character already exists
		characterAdded(player.Character)
	end

	-- runs when character is added
	player.CharacterAdded:Connect(characterAdded)
end

-- The for loop gets players in game who were added before the player added listener could connect
for _, player in ipairs(Players:GetPlayers()) do
	playerAdded(player)
end

-- Each time a new player is added after for loop
Players.PlayerAdded:Connect(playerAdded)

Can’t you think by yourself, even a tiny little bit?

When the player respawns, the oldHealth variable will equal to zero and the newHealth variable will equal to a hundred: therefore, the if conditional will return false and won’t execute the code instructions that modify the health bar status.

As a side note, I recommend you to add a tween instead of just resizing the bar.