I wanna have leaderboards in my game update to say a 5 minute timer. However, whenever they update, I don’t want the UI to be wiped, and recreated with new UI elements, as that’ll cause performance issues (I have 5 leaderboards, 4 of which have daily/weekly/alltime, therefore 13 leaderboards need 50 players listed, 650 frames created every 5 minutes)
I wanna know of a way to make it so it doesn’t require deleting the frames, but I can still update users on the board or remove and add anybody else whose new to the board.
All I do atm is just load them all on start
function LeaderboardController:Create(leaderboardGui, parent, data)
local Template = leaderboardGui.UIListLayout.Template
-- Create ranks
for i, v in pairs(data) do
if tonumber(v.key) > 0 then
local Success, Error = pcall(function()
local NewFrame = Template:Clone()
NewFrame.Name = i
NewFrame.LayoutOrder = i
-- Set texts
NewFrame.Rank.Text = "#" .. i
NewFrame.PlayerName.Text = Players:GetNameFromUserIdAsync(v.key)
if parent.Parent.Parent.Name == "PlayTime" then
NewFrame.Total.Text = Library:ConvertTime(v.value, 3)
else
NewFrame.Total.Text = Library:BreakNumber(v.value)
end
-- Set rank extra info
local Data = RANK_DATA[i]
if Data then
NewFrame.Size = Data.Size
NewFrame.Rank.TextColor3 = Data.Color
NewFrame.Rank.UIStroke.Color = Library:MakeDarker(Data.Color)
end
NewFrame.Parent = parent
-- Update ScrollingFrame CanvasSize
parent.CanvasSize = UDim2.fromOffset(
0,
parent.UIListLayout.AbsoluteContentSize.Y
)
end)
end
end
end
Creating new UI elements would not cause performance issues unless you’re generating thousands. Even then, updating existing UI elements isn’t going to be that big of a performance improvement. If there’s any issues, it’s likely some other part of your code.
I’m not asking about performance issues. As I said, I’d have to be creating 650 new frames every 5 minutes. Inside those frames is 3 text labels. So that’s 2,600 new UI elements every 5 minutes. I don’t want to do that. I want to find a way to have them just update as necessary
You are not understanding what I am asking for. I am wanting to know of a way to efficiently update the leaderboards every 5 minutes, where I can change whoever is on the leaderboards score with the most up to date one, or if I need to delete remove people
You’re not understanding what I’m saying either. You don’t need to update every single one. All you need to update are the ones that would be visible within scrollframe at that position. You don’t need to have thousands of UI elements.
No, I am understanding what you are saying, you are not understanding what I am wanting though. This has nothing to do with updating based on scrolling frame position and what not. All the elements are created when you join once, so they out of the way, no performance issues. The issue is having to delete and recreate them every 5 minutes, I don’t want to do that
Why are you doing that? The client should only load in the amount that would fit within the visible window. When it receives an update, it can update the specific visible frames with the correct data. There wouldn’t be any issues as you’re only destroying or creating maybe 5 or 10 frames every 5 minutes, plus whenever they scroll.
I’m looking for a fix that’ll take me 15 minutes to add. Not something that’d require an entire rewrite and having to figure out all the math behind it
The math isn’t complicated. Regardless, I’m not aware of any magic bullet that would help you. Maybe somebody else has an easier idea. Or you can wait for Roblox to eventually do their UI overhaul, but I doubt they’ll be doing that anytime soon.
Can’t really provide any scripts with what you’ve given but what you would do is iterate over the OrderedDataStore data fetched from “:GetSortedAsync()” and do the following.
local Players = game:GetService("Players")
local DataStores = game:GetService("DataStoreService")
local DataStore = DataStores:GetOrderedDataStore("DataStore")
local Gui = script.Parent
local function PopulateGui()
local Pages = DataStore:GetSortedAsync() --Returns a pages object.
local Page = Pages:GetCurrentPage() --Get the current (first) page.
for Index, Data in ipairs(Page) do --Page is the data returned by GetSortedAsync.
local UserId = Data.key --Assume the key field is the UserId.
local Username = Players:GetNameFromUserIdAsync(tonumber(UserId)) --Remember that DataStore keys are string values.
local Value = Data.value --Assume the value field is the value.
local Frame = Gui:FindFirstChild("Frame"..Index) --Incrementing naming scheme required.
if Frame then
local UserIdLabel = Frame:FindFirstChild("UserIdLabel"..Index)
if UserIdLabel then
UserIdLabel.Text = UserId
end
local UsernameLabel = Frame:FindFirstChild("UsernameLabel"..Index)
if UsernameLabel then
UsernameLabel.Text = Username
end
local ValueLabel = Frame:FindFirstChild("ValueLabel"..Index)
if ValueLabel then
ValueLabel.Text = tostring(Value) --Likely to be a number/integer value.
end
local IconLabel = Frame:FindFirstChild("IconLabel"..Index) --Player icon.
if IconLabel then
IconLabel.Image = Players:GetUserThumbnailAsync(tonumber(UserId), Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size420x420)
end
end
end
end
Hopefully I’ve added enough comments so everything should make sense, I was under the impression that the gui was a “SurfaceGui” instance so everything can be easily contained in a single server script.
The trick is to just name the GuiObjects in a way such that they can be easily referenced while iterating over the data returned by “:GetSortedAsync()”.
This way you aren’t recreating the same instances over and over again, you’re just referencing the already existing instances and updating their properties accordingly.
I don’t have a problem with creating the elements. My leaderboards all work as intended. My only issue is I want to ADD a way to have my leaderboards update every 5 minutes. As I said, they only load on start. They do not update.
@MightyDantheman has put you on the right track, you don’t need 650 frames, you only need the frames that are visible to the user to be updated periodically.
I don’t want to reiterate over already existing DevForum posts, so if you intend to take that route (which is the most optimal), you can find it here: How do I optimize a scrolling frame for over 1000 frames?. The post linked covers all the math you will need.
I understand you want a solution that takes 15 minutes to add, although I’d still suggest what Dan has given you, as it solves your problem with performance and scales easier if you ever intend to have more than 650 frames.
I’d like to further note that if you want a less optimal way to extend your current solution, you could have a list of all UI elements in a table. This allows you to add people by pushing the indices downwards and inserting an index somewhere in between with that user.
You wouldn’t need to create new UI elements, only once, and all you would need to ultimately do is update the UI elements (as in just the text.)
Although this solution isn’t ideal as iirc Roblox still renders anything that isn’t visible in scrolling frames so in theory 650 text labels updating at once could still cause frame drops which is why only updating visible frames is still your best choice. Plus you’d still be rendering 650 frames (or more if you extend the amount of users displayed) regardless of visibility.