Hey guys! Today I will be teaching you how to make a Global Leaderboard like you see in all those simulator games.
(Thats what it’ll look like!)
Making the currency
The first thing we need is a currency (or stat) to display on the leaderboard. For this tutorial I will be making a coins leaderstats and a system that adds 50 coins every 5 seconds to the player.
To make this we need a script in ServerScriptService for orginization, we will call it leaderstats.
Firstly we will make a function that fires when the player joins the game and adds a Folder inside the player called leaderstats. Important Notice: The Folder NEEDS to be names exactly leaderstats or else the player will not be able to see their currency in the player list.
local function OnPlayerAdded(player)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = player
end
Next we want to add a stat to this folder, as I mentioned I will be doing coins and I will use an IntValue for this:
local function OnPlayerAdded(player)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = stats
end
Now you should have something that looks like this:
The last thing we want to in this function is make the player get 50 coins every 5 seconds. For this we will spawn a new thread (so that any thing else can still run in this script) using task.spawn.
local function OnPlayerAdded(player)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = stats
task.spawn(function()
while task.wait(5) do
coins.Value += 50
end
end)
end
Finally, we want to make a Players Service variable and connect this function to a PlayerAdded event:
--// Services
local Players = game:GetService("Players")
--// Functions
local function OnPlayerAdded(player)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = stats
task.spawn(function()
while task.wait(5) do
coins.Value += 50
end
end)
end
--// Connections
game.Players.PlayerAdded:Connect(OnPlayerAdded)
Saving the data
In this tutorial we will be using OrderedDataStore
.
First, open up your leaderstats script and at the top make two new variables: A DataStoreService variable and a variable for your DataStore (I’m calling my data store CoinsBoard):
local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetOrderedDataStore("CoinsBoard1")
After you have that we want to go in our player added function (that we made before), add a plr_key variable (this will be the key we use to access the player’s data) and at the very top try and recieve the data, using a pcall (protected call) function.
local plr_key = "id_"..player.UserId.."_Coins"
local success, data = pcall(function()
return DataStore:GetAsync(plr_key)
end)
This function will give us our data/coins back in a variable called data, aswell as telling us if the call was successful or not. We will now use this to load or coins value:
if success then
coins.Value = data or 0 -- 0 is the default value e.g. if this is the first time a player joined.
end
Now that we have successfully loaded our data we must now save it, here is the full PlayerAdded function:
--// Services
local Players = game:GetService("Players")
--// Functions
local function OnPlayerAdded(player)
local plr_key = "id_"..player.UserId.."_Coins"
local success, data = pcall(function()
return DataStore:GetAsync(plr_key)
end)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Parent = stats
if success then
coins.Value = data or 0
end
task.spawn(function()
while task.wait(5) do
coins.Value += 50
end
end)
end
--// Connections
game.Players.PlayerAdded:Connect(OnPlayerAdded)
Alright so for the saving of data we will need to connections, PlayerRemoving
and game:BindToClose
one event runs when the Player leaves the server
while the other runs when the server shuts down
.
Saving is a pretty simple task. Player leaves (or server shuts down) call a DataStore method (SetAsync) and set the value to the player’s coins value. Just like this:
local function OnPlayerRemoving(player)
end
local function OnServerShutdown()
end
Okay. We will start with the OnPlayerRemoving
function. Firstly we need the SAME EXACT player key as before:
local plr_key = "id_"..player.UserId.."_Coins"
after that we will get the coins from the player:
local coins = player.leaderstats.Coins
finally we will make another pcall and save the data:
local success, result = pcall(function()
return DataStore:SetAsync(plr_key, coins.Value)
end)
After we save the data we want to check if it was successful or not. If not, then we want to warn the error which will be stored in result.
if not success then
warn(result)
end
So our PlayerRemoving should look like this:
local function OnPlayerRemoving(player)
local plr_key = "id_"..player.UserId.."_Coins"
local coins = player.leaderstats.Coins
local success, result = pcall(function()
DataStore:SetAsync(plr_key, coins.Value)
end)
if not success then
warn(result)
end
end
Now we copy everything in our PlayerRemoving function into our OnServerShutdown
function and just wrap it in a for loop that gets every player. So our OnServerShutdown
should look like this:
local function OnServerShutdown()
for _, player in pairs(game:GetService("Players"):GetPlayers()) do
local plr_key = "id_"..player.UserId.."_Coins"
local coins = player.leaderstats.Coins
local success, result = pcall(function()
DataStore:SetAsync(plr_key, coins.Value)
end)
if not success then
warn(result)
end
end
end
Now last thing for this section is to connect the functions to their events:
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(OnServerShutdown)
Our final leaderstats code should look like this:
--// Services
local Players = game:GetService("Players")
local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetOrderedDataStore("CoinsBoard1")
--// Functions
local function OnPlayerAdded(player)
local plr_key = "id_"..player.UserId.."_Coins"
local success, data = pcall(function()
return DataStore:GetAsync(plr_key)
end)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Parent = stats
print(success, data)
if success then
coins.Value = data or 0
end
task.spawn(function()
while task.wait(5) do
coins.Value += 50
end
end)
end
local function OnServerShutdown()
for _, player in pairs(game:GetService("Players"):GetPlayers()) do
local plr_key = "id_"..player.UserId.."_Coins"
local coins = player.leaderstats.Coins
local success, result = pcall(function()
DataStore:SetAsync(plr_key, coins.Value)
end)
if not success then
warn(result)
end
end
end
local function OnPlayerRemoving(player)
local plr_key = "id_"..player.UserId.."_Coins"
local coins = player.leaderstats.Coins
local success, result = pcall(function()
DataStore:SetAsync(plr_key, coins.Value)
end)
if not success then
warn(result)
end
end
--// Connections
game.Players.PlayerAdded:Connect(OnPlayerAdded)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(OnServerShutdown)
The actual leaderboard
Now the final section. The one you’ve all been waiting for. The actual leaderboard. Now, the setup itself is pretty easy but theirs a few things you need. To make things easier, here is a model of the leaderboard I made (it doesn’t include the script).
Okay, lets get started on the scripting. Make a script (normal script) inside of the leaderboard model and open it up.
We will start off by assigning our variables, both general and UI:
--// GENERAL VARIABLES
local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetOrderedDataStore("CoinsBoard1")
--// UI VARIABLES
local UI = script.Parent.SurfaceGui
local basePlayerFrame = UI.BasePlayerFrame
local boardFrame = UI.ScrollingFrame
After our variables, we will get started with our functions. The first one is just a copy of the BindToClose
function from before (we called it OnServerShutdown) and rename it to SaveData:
--// Functions
local function SaveData()
for _, player in pairs(game:GetService("Players"):GetPlayers()) do
local plr_key = "id_"..player.UserId.."_Coins"
local coins = player.leaderstats.Coins
local success, result = pcall(function()
DataStore:SetAsync(plr_key, coins.Value)
end)
if not success then
warn(result)
end
end
end
So the next function we will make is one that will get us our Top50Players as we will be doing a top 50 coins leaderboard.
local function getTop50Players()
local isAscending = false
local pageSize = 50
local pages = DataStore:GetSortedAsync(isAscending, pageSize)
local top50 = pages:GetCurrentPage()
local top = {}
for rank, data in ipairs(top50) do
local dataName = data.key
local name = game:GetService("Players"):GetNameFromUserIdAsync(dataName:split('_')[2])
local coins = data.value
local currentPlayer = { Player = name, Coins = coins, Rank = rank, }
table.insert(top, rank, currentPlayer)
end
return top
end
So let’s break down that function. We first make some variables. The pageSize
variable tells us how many players (max) we want to get back. isAscending
represents the order, if it’s false then the player with the highest amount of coins will be on top (and if its true then the lowest amount will be on top). pages
gives us our results and top50
gives us our top50 players. Finally we have an empty top
table that we will fill up with all the top players.
To do that, we loop through our top50 table and insert a dictionary (storing the Player’s Name, Coins, and Rank) into the top table. We also return the top table at the end so we can loop through it later and get all the players aswell as their Name, Coins and Rank.
The next function we will make is one we will use. to clear the list.
local function ClearList()
task.spawn(function()
for _, plrFrame in pairs(boardFrame:GetChildren()) do
if not plrFrame:IsA("Frame") then continue end
plrFrame:Destroy()
task.wait(0.25)
end
end)
end
This function will loop through everything in the board if it is not a frame (e.g it is a UIListLayout) then it will skip that iteration using the guard clause (if). Then it will destroy the frame. Note the task.wait(0.25)
is optional, I put it there to give it the deleting 1-by-1 effect.
This next (and final) function will be the one that updates the list. This one is the biggest, so we’ll go step-by-step.
First we start off by declaring the function and calling our SaveData()
and ClearList()
functions.
local function UpdateList()
SaveData()
ClearList()
end
after we call those two methods we want to get our Top 50 players (using the function from before)
local top50 = getTop50Players()
after that we want to spawn a new thread, and loop through all of our Top 50 players using an ipairs loop so it goes in order.
task.spawn(function()
for _, plr in ipairs(top50) do
end
end)
Inside of that loop, we want to do a few things. Clone the base frame and set the parent to the board.
Then we want to set the Plr (player name text label), Amount (The TextLabel for the amount of coins the player has), and the Rank (the text label that displays the players rank on the leaderboard).
All that information comes from the Plr
dictionary that we get by looping through our Top 50.
Finally we want to make the frame visible and task.wait(0.25)
so that we get the effect of the players being added 1-by-1.
local frame = basePlayerFrame:Clone()
frame.Parent = boardFrame
frame.Plr.Text = plr.Player
frame.Amount.Text = plr.Coins
frame.Rank.Text = plr.Rank
frame.Visible = true
task.wait(0.25)
Alright, thats it for that function:
local function UpdateList()
SaveData()
clearList()
local top50 = getTop50Players()
task.spawn(function()
for _, plr in ipairs(top50) do
local frame = basePlayerFrame:Clone()
frame.Parent = boardFrame
frame.Plr.Text = plr.Player
frame.Amount.Text = plr.Coins
frame.Rank.Text = plr.Rank
frame.Visible = true
task.wait(0.25)
end
end)
end
Okay, so now the last thing we want to do is update the leaderboard every minute (60 seconds and also have a countdown). Don’t do anything less or else Roblox will start yelling at you about making to many requests (lol).
So to do this we want to spawn a new thread, have a while loop, and then a for loop that will update the text evey second. Very very simple. Oh ya and also yk call the UpdateList()
function.
task.spawn(function()
while true do
UpdateList()
for count=60,0,-1 do
script.Parent.Part.SurfaceGui.Count.Text = "Leaderboards Updating In: "..count
task.wait(1)
end
end
end)
So yeah. Thats it. That was the last thing. We are done:
How Did I Do On This Tutorial, 1-10.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
0 voters
EDIT: BRAND NEW VIDEO TUTORIAL IS HERE