Welcome!
Stage Selectors are vital parts of difficulty chart obbies but are good additions to think of for any obby game you choose to create. Let’s get started!
Step 1: Creating the UI
Skip this step if you have already created UI!
I am by no means a UI designer, so I got help from @GamersInternational and remixed their UI to create a renewed and worse-looking stage selector:
You can get the UI file here:
https://www.roblox.com/library/6923714062/Stage-Selector-UI
Step 2: Naming things properly
This will be more of a checklist than a step:
- TextBox in the UI is named “Input”;
- Left and Right arrows are named “Left” and “Right” respectively:
- SpawnLocation for initial spawning named “0”;
- Parts for checkpoints in the obby named sequential numbers (i.e. 1st checkpoint named “1” and 2nd checkpoint named “2” &c.):
All good? Let’s move on to Step 3!
Step 3: Scripting the Leaderboard
The Leaderboard is a crucial step to the Stage Selector. In this tutorial, we will not be working with DataStores, so data will not save. You can read other tutorials for this information.
Here’s the script. Place this in ServerScriptService under a normal Script with any name you please:
local Players = game:GetService("Players")
local function createLeaderstats(player)
local leaderstatsContainer = Instance.new("Folder")
leaderstatsContainer.Name = "leaderstats"
leaderstatsContainer.Parent = player -- creates leaderstats. vital.
local stageNumber = Instance.new("IntValue")
stageNumber.Name = "Stage"
stageNumber.Parent = leaderstatsContainer -- creates the "Stage" variable
stageNumber.Value = 3 -- set to 3 for testing, in a live game set this to 0
end
Players.PlayerAdded:Connect(createLeaderstats)
Step 4: Creating the Client Sided Events
There will be 3 scripts in this section of the tutorial; however, first, you’ll need to create a RemoteEvent named StageSelector and place it in ReplicatedStorage.
- Place this script in Input, under a LocalScript:
local Rep = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
script.Parent.Text = tostring(game:GetService("Players").LocalPlayer:WaitForChild("leaderstats"):WaitForChild("Stage").Value) -- updates stage number on death
script.Parent.FocusLost:Connect(function(enterPressed)
if enterPressed then
Rep:WaitForChild("StageSelector"):FireServer(script.Parent.Text)
end
end)
Players.LocalPlayer:WaitForChild("leaderstats"):WaitForChild("Stage").Changed:Connect(function(val)
script.Parent.Text = tostring(val) -- updates stage number on advancing
end)
- Place this script in Left, under a LocalScript:
local Rep = game:GetService("ReplicatedStorage")
local input = script.Parent.Parent.Input
script.Parent.Activated:Connect(function()
if tonumber(input.Text) == 0 then -- prevents the stage selector from going into negative numbers
return
end
input.Text = tostring(tonumber(input.Text) - 1) -- converts string to number to do arithmetic, then re-converts.
Rep:WaitForChild("StageSelector"):FireServer(input.Text)
end)
- Place this in Right, under a LocalScript:
local Rep = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local input = script.Parent.Parent.Input
script.Parent.Activated:Connect(function()
if tonumber(input.Text) >= Players.LocalPlayer:WaitForChild("leaderstats"):WaitForChild("Stage").Value then -- prevents the stage selector from going above the actual value
return
end
input.Text = tostring(tonumber(input.Text) + 1) -- converts string to number to do arithmetic, then re-converts.
Rep:WaitForChild("StageSelector"):FireServer(input.Text)
end)
Step 5: Creating the server-side handler
This is the most important, yet shortest, script. It consists of the teleportation and sanity check.
Place this in a normal Script under ServerScriptService:
local Rep = game:GetService("ReplicatedStorage")
Rep:WaitForChild("StageSelector").OnServerEvent:Connect(function(plr, level)
if tonumber(level) <= plr.leaderstats.Stage.Value then -- sanity check. note that we don't have to wait for the child since the client already did that
local tpTarget = workspace:FindFirstChild(level) -- finds the part that we named, for example, "23", in the workspace
plr.Character:WaitForChild("Head").CFrame = tpTarget.CFrame + Vector3.new(0, 3, 0) -- teleports the player
end
end)
Step 6: Testing
If something is broken here, read the output and double-check your scripts. Here’s how it should look:
Thank you for checking my tutorial! If you’d like, please complete these polls:
- 1
- 2
- 3
- 4
- 5
0 voters