CUBE BURSTSTUDIOS
obby-checkpoints.zip
Details

Obby Checkpoints with Saving

Numbered checkpoints that remember each player's stage, with no stage skipping. Drop in and build your obby.

Category
Code
File
obby-checkpoints.zip
Size
1.8 KB
Downloads
0
Added
16 Oct 2026
Licence
Free to use, no credit needed (CC0)

#obby#checkpoints#stages#spawn#saving#luau#roblox#script

⚑ Report this

Numbered checkpoints that remember each player's stage, with no stage skipping. Drop in and build your obby.

Touch a checkpoint to unlock it; you respawn at your highest stage, and it's remembered next time you play.

SETUP
1. In Workspace make a Folder called "Checkpoints".
2. Put SpawnLocations inside named 1, 2, 3, ... in order. (Set their Neutral = true, AllowTeamChangeOnTouch = false.)
3. Put this Script in ServerScriptService. Publish and enable "Studio Access to API Services" to test saving.
A "Stage" stat appears on the leaderboard.

The main script is shown below with a Copy button, or grab the download with every file and a README.

ObbyCheckpoints.server.lua
--[[
	Obby Checkpoints (with saving)  ·  by Cube Burst Studios  ·  CC0
	Touch a checkpoint to unlock it; you respawn at your highest stage, and it's remembered next time you play.

	SETUP
	1. In Workspace make a Folder called "Checkpoints".
	2. Put SpawnLocations inside named 1, 2, 3, ... in order. (Set their Neutral = true, AllowTeamChangeOnTouch = false.)
	3. Put this Script in ServerScriptService. Publish and enable "Studio Access to API Services" to test saving.
	A "Stage" stat appears on the leaderboard.
]]

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")

local STORE = DataStoreService:GetDataStore("ObbyStage_v1")
local folder = workspace:WaitForChild("Checkpoints")

local function checkpoint(stage)
	return folder:FindFirstChild(tostring(stage))
end

local function stageOf(player)
	local stats = player:FindFirstChild("leaderstats")
	local value = stats and stats:FindFirstChild("Stage")
	return value
end

local function setRespawn(player)
	local value = stageOf(player)
	local spawn = value and checkpoint(value.Value)
	if spawn then
		player.RespawnLocation = spawn
	end
end

Players.PlayerAdded:Connect(function(player)
	local stats = player:FindFirstChild("leaderstats")
	if not stats then
		stats = Instance.new("Folder")
		stats.Name = "leaderstats"
		stats.Parent = player
	end
	local stage = Instance.new("IntValue")
	stage.Name = "Stage"
	stage.Value = 1
	stage.Parent = stats

	local ok, saved = pcall(function()
		return STORE:GetAsync("stage_" .. player.UserId)
	end)
	if ok and type(saved) == "number" and checkpoint(saved) then
		stage.Value = saved
	end
	player:SetAttribute("StageLoaded", ok)
	setRespawn(player)
	player.CharacterAdded:Connect(function()
		setRespawn(player)
	end)
	if player.Character then
		player:LoadCharacter() -- put them at their saved stage straight away
	end
end)

Players.PlayerRemoving:Connect(function(player)
	local value = stageOf(player)
	if value and player:GetAttribute("StageLoaded") then
		pcall(function()
			STORE:UpdateAsync("stage_" .. player.UserId, function(old)
				return math.max(type(old) == "number" and old or 1, value.Value)
			end)
		end)
	end
end)

-- touching a checkpoint: only move forward, one stage at a time (no skipping ahead)
for _, spawn in ipairs(folder:GetChildren()) do
	local number = tonumber(spawn.Name)
	if number and spawn:IsA("BasePart") then
		spawn.Touched:Connect(function(hit)
			local player = Players:GetPlayerFromCharacter(hit.Parent)
			local value = player and stageOf(player)
			local humanoid = hit.Parent:FindFirstChildOfClass("Humanoid")
			if value and humanoid and humanoid.Health > 0 and number == value.Value + 1 then
				value.Value = number
				player.RespawnLocation = spawn
			end
		end)
	end
end

MORE
CODE

View all ↗