Math and UDIM2 Variables

I’m trying to add textbuttons that displays all active players usernames to a scrollingframe. Heres the GUI, and on the left Is the scrolling frame:


Heres how It’s supposed to look:

Heres how It looks:

Code:

local playerList = script.Parent
local template = script.Parent.Parent.template

local createdButtons = {}

local yScale = 0
local finaludim2 = UDim2.new(0, 0, 0, 0)

while true do
	for _, existingPlayer in ipairs(playerList:GetChildren()) do
		if existingPlayer:IsA("TextLabel") and existingPlayer ~= template and not createdButtons[existingPlayer.Name] then
			existingPlayer:Destroy()
		end
	end

	finaludim2 = UDim2.new(0, 0, yScale, 0)

	for _, player in ipairs(game.Players:GetPlayers()) do
		if not createdButtons[player.Name] then
			local cloned = template:Clone()
			cloned.Parent = playerList
			cloned.Name = player.Name
			cloned.Text = player.Name
			cloned.Visible = true
			cloned.UID.Value = player.UserId
			cloned.Position = finaludim2
			yScale = yScale + 0.075

			createdButtons[player.Name] = true
		end
	end

	wait()
end

May I suggest you use a UIListLayout instead of doing the math manually? They will autoformat all UI children in a Frame to appear how you want them.

UIListLayout | Documentation - Roblox Creator Hub

1 Like

This did fix It, thank you. But would It be possible to do It manually?

Yes, it is. I’m not quite sure what the issue is in your code excerpt, but it’s probably a result of yScale not being properly increased. Could be the use of ipairs, not quite sure

You’re welcome to try to diagnose the issue, but again, the UIListLayout is the much easier solution here.

Hi Jarred, I saw that you want to make a list manually and so without using UIListLayout, it’s understandable! Let me show you how you can achieving this result and how to improve your code a little to make it a little more performing.

Use a loop like you do may seem to be the solution to continually update the list. But we would agree to say that you don’t need to update your list every second. We need to update it only when necessary like when a player join or leave and when the resolution screen have changed to update the position and the canvas size!

You are probably wondering how you will know when you need to update the list? It’s simpler than you think! Every Instance on roblox have the signals ChildAdded and ChildRemoved, so you can use it to update your list! To do this, we are going to transform your code a little. We will put the content of your loop in a function, you can name this function like you want, for this example I named it “updatePlayerList”, it’s a name that aptly describes its utility!

Now that we have this function, we can remove your variables yScale and finaludim2; we no longer need them! Instead, we will create a variable named index above the loop which create new display and under the loop which destroys the displays which we no longer need. This variables will serve us to know the position of the display that we are creating or modifying.

Also we will assign the value of createdButtons[PlayerName] to the cloned template. This would make it easier for us when we would like to destroy it.

We will also move the position assignment of the display out of your condition to be able to update it when a player leaves, joins, or when the screen resolution changes.

Now that we have changed the position of the display, we can add 1 to index for the next display that will be modified.

After the completion of the loop that creates and updates the displays, we can now utilize index to determine the number of displays in the list and update the CanvasSize of your ScrollingFrame. I assume that playerList is a ScrollingFrame ; if not, simply adjust the code to make it compatible with your UI.

I haven’t found an effective way to know the AbsoluteSize of the templates so I’ve use FindFirstChildWhichIsA to find an instance with the same ClassName as your template. I use a ternary operation to know if the result is an Instance and if it is I use the AbsoluteSize of this instance to multiply it with our variable index. You have now the perfect size for your CanvasSize!

You can use the signal GetPropertyChangedSignal to know when the size of your list updated to update all displays position and the CanvasSize of the ScrollingFrame.

Since the player who sees the list will not be notified by their own joining we must initialize your new function at the end of the code.

This is the final result after the modifications:

-- Services
local playerService = game:GetService("Players")

-- Variables
local playerList = script.Parent
local template = script.Parent.Parent.template

local createdButtons = {}

-- Functions
local function updatePlayerList()
	-- Destroy display which we no longer need
	for playerName, frame in pairs(createdButtons) do
		-- Try to find the player in the service
		local player = playerService:FindFirstChild(playerName)
		if (not player) then
			-- Destroy
			frame:Destroy()
                        
			-- Remove from "register"
			createdButton[playerName] = nil
		end
	end
	
	-- Create new template
	local index = 0
	for _, player in pairs(playerService:GetPlayers()) do
		-- Player Name
		local playerName = player.Name
		
		-- Player already have a display?
		if (not createdButtons[playerName]) then
			-- New display
			local cloned = template:Clone()
			cloned.Name = playerName
			cloned.Text = playerName
			cloned.UID.Value = player.UserId
			cloned.Visible = true
			cloned.Parent = playerList
			
			-- Store into createdButtons
			createdButtons[playerName] = cloned
		end
		
		-- Update existing frame
		local frame = createdButtons[playerName]
		frame.Position = UDim2.new(0, 0, 0, frame.AbsoluteSize.Y * index)
		
		-- Update Index
		index += 1
	end
	
	-- Update canvas size
	local frame = playerList:FindFirstChildWhichIsA(template.ClassName)
	local ySize = ((typeof(frame) == "Instance") and frame.AbsoluteSize.Y * index or 0)
	playerList.CanvasSize = UDim2.new(0, 0, 0, ySize)
end

-- Connections
playerService.ChildAdded:Connect(updatePlayerList) -- Update list when a player enter.
playerService.ChildRemoved:Connect(updatePlayerList) -- Update list when a player leave.
playerList:GetPropertyChangedSignal("AbsoluteSize"):Connect(updatePlayerList) -- Update list when the screen resolution change.

-- Initialize
updatePlayerList()

I hope I have helped you to understand how to make it work better, if you have question, don’t hesitate to ask me!

1 Like

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