BeginnerObbyCollectionServiceRespawnServer

Obby Checkpoint System

A classic obby checkpoint flow. Touching a checkpoint sets the player's spawn point — and stays set across deaths and re-joins. Each player has their own checkpoint independently.

1 file84 lines of Luau
The Prompt

Build me an obby checkpoint system. Each checkpoint is a part. When a player touches one, they save it as their spawn. When they die, they respawn at their last checkpoint. Each player should have their own progression.

Paste this — or any variation — into StudByStud and you’ll get the code below in seconds.

How it works

  • Each checkpoint part is tagged 'Checkpoint' in Studio. Order matters only if you want to prevent skipping — the basic version awards any checkpoint a player touches.
  • When the player touches a checkpoint, the server stores it in Player.RespawnLocation, which Roblox uses automatically when the character respawns.
  • We also save the checkpoint number as a player attribute so other systems (UI, leaderboard) can read it cheaply.
  • On CharacterAdded we re-apply the saved spawn so a freshly-respawned player still uses their last checkpoint, not the default lobby spawn.
  • To prevent skipping, the version below also tracks the checkpoint number and refuses to assign a checkpoint that's lower than the player's current one.

The generated code

One file. Copy it into Roblox Studio at the path shown.

File 1 of 1Script
ServerScriptService/CheckpointService.lualuau
--!strict
-- CheckpointService.lua
local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")

local CHECKPOINT_TAG = "Checkpoint"

-- Each tagged part should have an IntValue named "Order" (1, 2, 3, ...) so we
-- can reject players touching a lower checkpoint than they've already reached.
local function getOrder(part: Instance): number
	local v = part:FindFirstChild("Order")
	if v and v:IsA("IntValue") then
		return v.Value
	end
	return 0
end

local function onCheckpointTouched(part: BasePart, hit: BasePart)
	local character = hit:FindFirstAncestorOfClass("Model")
	if not character then return end
	local player = Players:GetPlayerFromCharacter(character)
	if not player then return end

	local order = getOrder(part)
	local current = player:GetAttribute("CheckpointOrder") :: number? or 0
	if order <= current then return end

	player:SetAttribute("CheckpointOrder", order)
	player.RespawnLocation = part :: any
end

local function setupCheckpoint(part: Instance)
	if not part:IsA("BasePart") then return end
	part.Touched:Connect(function(hit)
		onCheckpointTouched(part, hit)
	end)
end

for _, part in CollectionService:GetTagged(CHECKPOINT_TAG) do
	task.spawn(setupCheckpoint, part)
end
CollectionService:GetInstanceAddedSignal(CHECKPOINT_TAG):Connect(setupCheckpoint)

-- Re-apply saved spawn whenever the character respawns. Roblox uses
-- player.RespawnLocation automatically, but only if it's still set when the
-- next character loads — clearing on death would break the flow.
local function onCharacterAdded(player: Player, character: Model)
	-- Wait one frame so the spawn happens, then we don't actually need to do
	-- anything else: Roblox already used RespawnLocation. This hook exists so
	-- you can extend it (play a sound, fire a checkpoint UI, etc.).
	task.wait()
	local order = player:GetAttribute("CheckpointOrder") :: number? or 0
	if order > 0 then
		print(`{player.Name} respawned at checkpoint {order}`)
	end
end

local function onPlayerAdded(player: Player)
	player:SetAttribute("CheckpointOrder", 0)
	player.CharacterAdded:Connect(function(char) onCharacterAdded(player, char) end)
	if player.Character then
		onCharacterAdded(player, player.Character)
	end
end

Players.PlayerAdded:Connect(onPlayerAdded)
for _, player in Players:GetPlayers() do
	task.spawn(onPlayerAdded, player)
end

Wires up every tagged checkpoint and binds it to per-player spawn state. Prevents skipping by tracking the highest checkpoint each player has reached.

What you’ll learn

Per-player checkpoint state via attributesPlayer.RespawnLocationCollectionService tags for designer-friendly setupCharacterAdded vs PlayerAdded for respawn handling

Want this built for your game?

Sign up, paste the prompt above, and StudByStud will generate it — and sync it straight into Roblox Studio. Free tier includes 1M Flash tokens per month.

Build it free