Creating a Stage Selector

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

:warning: Skip this step if you have already created UI! :warning:

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:

image

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:
    image
  • 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.):
    image

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.
image

  1. 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)
  1. 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)
  1. 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:

How helpful would you consider this tutorial?
  • 1
  • 2
  • 3
  • 4
  • 5

0 voters

15 Likes