Player Billboard Display help

This is my first time working with Billboards on players and I’m not sure why it’s not updating and also creates and error when the player dies.

image

local formatNumber = require(game:GetService("ReplicatedStorage"):FindFirstChild("FormatNumber"))

local function billboardRemoval(character)
	local head = character:FindFirstChild("Head")
	if head then
		local billboardGui = head:FindFirstChild("PlayerBillboardGui")
		if billboardGui then
			billboardGui:Destroy()
		end
	end
end

local function updateBillboardValues(billboard, cash, multi, rebirth)
	if billboard then
		if cash then
			billboard.Cash.Text = "Cash: "..formatNumber(cash.Value, formatNumber.FormatType.Suffix)
		elseif multi then
			billboard.Multi.Text = "Multi: "..formatNumber(multi.Value, formatNumber.FormatType.Suffix)
		else
			billboard.Rebirth.Text = "Rebirth: "..formatNumber(rebirth.Value, formatNumber.FormatType.Suffix)
		end
	end
end

game:GetService("Players").PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		if character and player.CharacterAppearanceLoaded:Wait() then
			local leaderstats = player:WaitForChild("leaderstats")
			local playerstats = player:WaitForChild("Playerstats")
			if leaderstats and playerstats then
				local cash = leaderstats:WaitForChild("Cash")
				local multi = playerstats:WaitForChild("Multi")
				local rebirth = playerstats:WaitForChild("Rebirth")
				if cash and multi and rebirth then
					local humanoid = character:WaitForChild("Humanoid")
					local head = character:WaitForChild("Head")
					if humanoid and head then
						local replicatedStorage = game:GetService("ReplicatedStorage")
						local playerBillboardGui = replicatedStorage:FindFirstChild("PlayerBillboardGui")
						if playerBillboardGui then
							local billboard = playerBillboardGui:Clone()
							billboard.Parent = head
							
							if billboard then
								billboard.Cash.Text = "Cash: "..formatNumber(cash.Value, formatNumber.FormatType.Suffix)
								billboard.Multi.Text = "Multi: "..formatNumber(multi.Value, formatNumber.FormatType.Suffix)
								billboard.Rebirth.Text = "Rebirth: "..formatNumber(rebirth.Value, formatNumber.FormatType.Suffix)
								
								task.wait()-- Give a short interval before refreshing billboard
								
								updateBillboardValues(billboard, cash, multi, rebirth)

								cash.Changed:Connect(function(Value)
									updateBillboardValues(billboard, cash, multi, rebirth)
								end)

								multi.Changed:Connect(function(Value)
									updateBillboardValues(billboard, cash, multi, rebirth)
								end)

								rebirth.Changed:Connect(function(Value)
									updateBillboardValues(billboard, cash, multi, rebirth)
								end)
							end

							-- Clean up the billboard when the humanoid dies
							humanoid.Died:Connect(function()
								billboardRemoval(character)
							end)
						end
					end
				end
			end
		end
	end)
end)

I apologize if the codes a bit of a mess I was moving sections around to see if I could find a solution.

2 Likes

I’ve ran into similar problems like this before. Essentially, since you have changed events connected to different leaderstats values that are constant and aren’t disconnected, when the leaderstats are updated, it will run both the new event connections, and the old ones.

tl;dr: It’s a memory leak, your code is trying to access old references because they aren’t properly cleaned up after the player dies.

The easiest way I can tell you to fix the problem is by disconnecting the event connections when the player dies and respawns:

-- Example
local eventConnections = {} -- this table holds all the currently connected event connections
table.insert(eventConnections, cash.Changed:Connect(function()
  ---...
end)) -- this adds the RBXScriptConnection to the eventConnections list

-- listen to when the player dies
humanoid.Died:Connect(function()
    for _, connection in eventConnections do
       connection:Disconnect() -- disconnect the connection so it doesn't run in the future
    end
end)

I was actually thinking about the cash problem (since it’s the only one at the moment causing the issue) and I believe it’s because I have a while loop running in the playerData script.

Do you think this would be the only issue I’ll run into or should I wrap all the changed events into the table you’ve advised?

Yes, but I’m glad you told me about the while loop. Over time with the creation of new player characters (respawning), there will be new while loop creations and the amount of money the player gets per WAIT_TIME will also increase.

To fix this is quite simple:

local playerIsAlive = true

-- inside the humanoid Died event, turn the boolean off
humanoid.Died:Connect(function()
   playerIsAlive = false
   ---...
end)

-- this will only run while the player is alive, preventing old or duplicate loops from being created
while playerIsAlive do
   task.wait(WAIT_TIME)
   ---...
end

You say it works when the player enters the game for the first time? But not once they respawn?

I should probably move the while loop to the billboard so it only runs while the billboard exists and player is alive (as you’ve stated). There really isn’t any reason to check for deaths anyway since no one will die in the game but I figured players will try anything so I’d better address it. The update problem still exists.

My guess is that because the cash.Changed event is still active, even after destroying the billboard, the cash.Changed event fires to attempt to update the cash text label. But since the player died and the billboardGui object no longer exists, but the reference to the billboardgui still exists within the billboard variable, there aren’t any children that truly exist in the billboard gui.

You can add a check to make sure the billboard gui still has a parent. I would add this to the updateBillboardValues() function.

local function updateBillboardValues(billboard, cash, multi, rebirth)
    if billboard then
        if billboard.Parent then -- Will make sure the billboard exists
            -- everything else here
        end
    end
end

If you can figure out any other way of verifying that the billboard variable contains a still-existing object would work.

1 Like

Thank you for the Parent check it worked well. The billboard updated the values. I think I know why the Multi isn’t updating though it’s probably because the while loop is hogging the function call even when the multi changes the cash is already been called. Should I use a coroutine for this or something (I’ve never done that before) – Is this a correct assertion?

image

Great to know it worked :slight_smile:
I thought the while loop was in a separate script? Yes, a coroutine for the while loop would allow the script to listen for event calls while simultaneously running the while loop.

Yeah I moved it to the billboard script.

I also created a new function for cash and made the coroutine for the while loop. Everything works as intended. Thanks to all that helped me understand all this. I had to choose a comment as solution but everyone here helped.

1 Like

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