Stage 2: Sphere Staircase + jump pad
Make sure Stage 1 works and resetting brings you back to the red Stage 2 checkpoint.
a sphere staircase and a Stage 3 checkpoint
how a tiny script can give a player a short upward push
a jump pad that makes the obby feel like parkour
The big idea
A jump pad is simple magic: touch the pad, get pushed upward for a tiny moment. Students see the result immediately, so the code feels worth typing.
- Touched
- an event that runs when something bumps into a part
- HumanoidRootPart
- the center part Roblox uses to move a character
- velocity
- speed in a direction
Build it
Step 1 — Build the sphere staircase
Add 5 anchored Ball parts after the Stage 2 checkpoint. Make each sphere a little higher and farther than the last.
- Name them
SphereStep_1throughSphereStep_5. - Keep them big enough to land on.
- Use bright colors so the path is easy to read.
Press Play and jump across them.
Step 2 — Build the jump pad
Add one part after the spheres:
Build this partJumpPad_1
BlockOpen recipe
JumpPad_1
Block- Size
- 8 × 1 × 8
- Color
- Cyan
- Material
- Neon
- Anchored
- ✓ Yes
- Place
- After the last sphere, before a small gap
- Target
- JumpPadTarget
Add one small marker part where the jump pad should send the player:
Build this partJumpPadTarget
BlockOpen recipe
JumpPadTarget
Block- Size
- 2 × 1 × 2
- Color
- Bright yellow
- Material
- Neon
- Anchored
- ✓ Yes
- Place
- On the landing side of the gap
Make JumpPadTarget transparent if you want it hidden.
Before you script the pad, add one RemoteEvent:
- In ReplicatedStorage, insert a RemoteEvent.
- Name it
LaunchPlayer.
Now add one client launcher script:
- In StarterPlayer > StarterPlayerScripts, insert a LocalScript.
- Name it
ParkourLaunchClient. - Paste this code:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local player = Players.LocalPlayer
local launchEvent = ReplicatedStorage:WaitForChild("LaunchPlayer")
launchEvent.OnClientEvent:Connect(function(launch)
local character = player.Character or player.CharacterAdded:Wait()
local root = character:FindFirstChild("HumanoidRootPart")
if not root then return end
root:ApplyImpulse(launch * root.AssemblyMass)
end)
Insert a Script inside JumpPad_1:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local pad = script.Parent
local target = workspace:WaitForChild("JumpPadTarget")
local launchEvent = ReplicatedStorage:WaitForChild("LaunchPlayer")
local FORWARD_POWER = 35
local JUMP_POWER = 100
local cooldown = {}
pad.Touched:Connect(function(hit)
local character = hit.Parent
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root then return end
local player = Players:GetPlayerFromCharacter(character)
if not player or cooldown[player] then return end
cooldown[player] = true
local direction = target.Position - pad.Position
local flatDirection = Vector3.new(direction.X, 0, direction.Z)
local launch = Vector3.new(0, JUMP_POWER, 0)
if flatDirection.Magnitude > 0 then
launch = launch + flatDirection.Unit * FORWARD_POWER
end
launchEvent:FireClient(player, launch)
task.delay(0.3, function()
cooldown[player] = nil
end)
end)
Press Play. Step on the pad and watch your character blast upward. The first test should feel obvious.
Step 3 — Add the Stage 3 checkpoint
Place a new SpawnLocation where the jump pad lands. Set it to a new color, add StageNumber = 3, and create the matching Stage 3 Team. Give this checkpoint the same settings as Stage 1 (check AllowTeamChangeOnTouch, uncheck Neutral, match the pad's TeamColor to its Team), and uncheck AutoAssignable on the new Team so players always start at Stage 1.
Understand it
The pad waits for a player to touch it. Then it finds the player's HumanoidRootPart and adds a short upward push toward JumpPadTarget.
The Script inside the pad decides when a launch should happen and sends the launch direction to LaunchPlayer. The LocalScript receives that message on the player's computer and calls ApplyImpulse on the player's own character. That matters because Roblox often lets the client own character physics. The script reads the direction from the pad to JumpPadTarget, so rotating the pad does not change the launch.
The important idea is not the long Roblox word. The idea is: touch part -> change motion.
Try this
Try this
Three short experiments. Predict before you run, then test your guess.
What will happen if JUMP_POWER changes from 100 to 50?
Test JUMP_POWER at 80, 100, and 120. Which launch feels exciting but still controllable?
Where else could a touch part change how the player moves?
Test your stage
- The sphere staircase is possible.
-
LaunchPlayerexists in ReplicatedStorage. -
ParkourLaunchClientexists in StarterPlayerScripts. - The jump pad launches upward and toward
JumpPadTarget. - The landing checkpoint has
StageNumber = 3. - Resetting after touching Stage 3 brings you back there.
If it breaks
- Nothing happens on the pad. Make sure the Script is inside
JumpPad_1. - The pad sees me but I do not launch. Check that
LaunchPlayeris in ReplicatedStorage andParkourLaunchClientis in StarterPlayerScripts. - The launch goes to the wrong place. Move
JumpPadTarget; do not rotate the pad to aim. - The launch is too weak. Raise
JUMP_POWER. - The launch is too wild. Lower
JUMP_POWERor move the landing closer. - The pad fires again and again. Check that
cooldown[player] = true,task.delay(0.3, ...), andcooldown[player] = nilare all in the script.
Do not over-explain velocity. Let students tune the number and feel the difference. The number-feel connection is the win.