Stage 10: Puzzle Room + publish & play in VR
Make sure you've finished Stage 9: Kinetic KillWall + VR ledge grab. This is the finale — you'll need your whole game working and your VRController complete with all its blocks.
a button-sequence puzzle room, a finish pad, and a Play-in-VR portal
how to track a sequence in code, how to publish a game, and how to playtest in VR
a published, VR-playable obby — and you finally put on the headset and play it
The big idea
This is the day it becomes a real game. No new tricks to dodge — just the last obstacle, the finish line, and the moment you've been building toward: the headset.
The final obstacle is a puzzle, not a hazard. Three buttons, one correct order. Press them right and the door opens; press them wrong and the sequence resets. You'll track that with a tiny bit of state — a number that remembers how far through the order you are. It's the same "tag parts, scan for them, react" habit you've used all course, now wired into logic instead of danger.
Then you close the loop. You'll do a comfort pass (one last look at your VR settings), publish your game to Roblox so it has a real link, build a Play-in-VR portal on the ExtensionPad to show it off, and finally — put on a headset and play the obby you built. Every VR feature you wrote blind, verified blind, gated behind if VRService.VREnabled — they all wake up at once. The climb, the comfort fade, the buzzes, the reveal, the danger sense, the grab-and-ride, the ledges. This is the playtest the whole course pointed at.
- ProximityPrompt
- a press-to-use prompt that appears near a part; works on a keyboard and in VR
- sequence / state
- remembering how far through an ordered list you are, with a number that counts up
- Publish to Roblox
- uploading your game so it has a real, shareable web link other people can play
- BillboardGui
- a UI that floats in the 3D world, facing the camera — perfect for a portal sign
- playtest
- playing your finished game to find what works and what to fix — here, finally in VR
Build it
Step 1 — Build the puzzle room
A small room at the end of the hall, with three buttons and a door.
Build this partPuzzleFloor
BlockOpen recipe
PuzzleFloor
Block- Size
- 24 × 1 × 24
- Color
- Medium stone grey
- Material
- Slate
- Anchored
- ✓ Yes
- Place
- Just past the Stage 10 pad — the final room's floor
Build this partPuzzleWall_Left
BlockOpen recipe
PuzzleWall_Left
Block- Size
- 1 × 12 × 24
- Color
- Dark stone grey
- Material
- Brick
- Anchored
- ✓ Yes
- Place
- Left edge of PuzzleFloor
Build this partPuzzleWall_Right
BlockOpen recipe
PuzzleWall_Right
Block- Size
- 1 × 12 × 24
- Color
- Dark stone grey
- Material
- Brick
- Anchored
- ✓ Yes
- Place
- Right edge of PuzzleFloor
Build this partPuzzleWall_Back
BlockOpen recipe
PuzzleWall_Back
Block- Size
- 24 × 12 × 1
- Color
- Dark stone grey
- Material
- Brick
- Anchored
- ✓ Yes
- Place
- Back edge of PuzzleFloor
Build this partFinishDoor
BlockOpen recipe
FinishDoor
Block- Size
- 8 × 10 × 1
- Color
- Bright orange
- Material
- Neon
- Anchored
- ✓ Yes
- Place
- A gap in the back wall — this opens when the puzzle is solved
CanCollide ON to start (it blocks you). The script opens it.
Now the three buttons on the back wall or floor:
Build this partButton_Green
BlockOpen recipe
Button_Green
Block- Size
- 3 × 3 × 1
- Color
- Lime green
- Material
- Neon
- Anchored
- ✓ Yes
- Place
- On the PuzzleFloor or back wall, easy to reach
Build Button_Red (Really red) and Button_Blue (Bright blue) the same way, spaced apart.
Step 2 — Script the button puzzle
Insert a server Script into ServerScriptService, name it PuzzlePanel, and type:
local CORRECT = { "Button_Green", "Button_Red", "Button_Blue" } -- the order
local progress = 1 -- how far we've got
local door = workspace:WaitForChild("FinishDoor")
local function press(name)
if name == CORRECT[progress] then
progress += 1 -- right button: advance
if progress > #CORRECT then
door.CanCollide = false -- solved: open the door
door.Transparency = 0.6
print("Puzzle solved — the door opens!")
end
else
progress = 1 -- wrong button: start over
end
end
-- Put a press-prompt on each button.
for _, buttonName in ipairs(CORRECT) do
local button = workspace:WaitForChild(buttonName)
local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Press"
prompt.HoldDuration = 0
prompt.Parent = button
prompt.Triggered:Connect(function()
press(buttonName)
end)
end
Press ▶ Play. Walk up to a button — a Press prompt appears. Press Green, then Red, then Blue, and the orange door opens. Press them out of order and it resets. ProximityPrompts work on a keyboard and in VR, so this puzzle is ready for the headset.
Step 3 — Build the finish pad and ExtensionPad
Behind the door is the celebration area — the same finish structure every Roblox course in this series shares.
- Insert a SpawnLocation past the door — the finish pad. Size
[8, 1, 8], anchored, a victory color (try Gold). Check AllowTeamChangeOnTouch, uncheck Neutral, match TeamColor. - Add a
StageNumberattribute (number) = 11. (Eleven is the finish sentinel — the value that means "they beat the obby.") - Add a Team named Finished, matching TeamColor, AutoAssignable unchecked.
Build this partExtensionPad
BlockOpen recipe
ExtensionPad
Block- Size
- 20 × 1 × 20
- Color
- Institutional white
- Material
- Marble
- Anchored
- ✓ Yes
- Place
- Behind the finish pad, in the celebration room
The shared end-of-course pad. Your Play-in-VR portal goes here.
Step 4 — The VR comfort pass
Before you publish, open VRController one last time and confirm every block is present and guarded. You're checking that nothing will make a headset player uncomfortable.
- Climb (Stage 1) — grip near
Climbablelifts you. - Comfort (Stage 2) —
HeadLocked = true,FadeOutViewOnCollision = true, re-center on the bumper. - Edge warning (Stage 3) — buzz when there's no floor below.
- Damage buzz (Stage 4) — buzz scaled to a hit, re-armed on respawn.
- Launch fade (Stage 5) — view eases dark during fast motion.
- Reveal wave (Stage 6) —
Hiddentiles light near your hand. - Danger sense (Stage 7) — buzz grows as boulders near your head.
- Grab & ride (Stage 8) — grip the
SweepArmto ride it.
Every block starts with if not VRService.VREnabled then return end (or is inside a VREnabled check). That guard is why your laptop testing stayed clean all course — and why these features switch on the instant a headset connects.
Step 5 — Publish to Roblox
- In Studio's top menu: File → Publish to Roblox.
- Give your game a name (e.g., VR Parkour Lab — First Name) and a short description.
- Publish. Roblox gives your game a real web page with a link.
- Set the game's privacy so your coach and family can play it (a coach can help with the account settings).
Step 6 — Build the Play-in-VR portal
Put a sign on the ExtensionPad that shows the game is VR-ready. Insert a BillboardGui into a small part on the ExtensionPad, add a TextLabel, and set its text to something like "Play in VR — [your game link]". A BillboardGui floats in 3D and always faces the player, so it reads from anywhere in the room.
This is your trophy: a published game, a portal that announces it, and the ExtensionPad finally holding this course's artifact — a VR-playable obby you built and shipped.
Step 7 — The headset playtest
Now the moment. Connect a VR headset (your coach will help), open your published game in VR, and play your obby start to finish.
Climb the first wall with your hands. Feel the comfort fade on the cannon launch. Feel the edge warning on the planks and the damage buzz on the kill bricks. Sweep your hand to reveal the hidden field. Feel the boulders bear down on your head. Grab and ride the sweeping arm. Climb the ledges over the kill wall. Solve the puzzle. Step onto the gold pad. Every feature you wrote blind, trusting the VREnabled guard — they're all alive at once. You built this, and now you're inside it.
How the puzzle tracks a sequence
No danger here — just logic. One number remembers your progress through the order; right presses advance it, wrong presses reset it. This is the same tag-and-react habit, pointed at a win condition.
local CORRECT = { "Button_Green", "Button_Red", "Button_Blue" }
local progress = 1
local door = workspace:WaitForChild("FinishDoor")
local function press(name)
if name == CORRECT[progress] then
progress += 1
if progress > #CORRECT then
door.CanCollide = false
door.Transparency = 0.6
print("Puzzle solved — the door opens!")
end
else
progress = 1
end
end
Lines 1–2The order, and where we are in it.
CORRECT lists the right sequence. progress is a number that starts at 1 — it points at the button we're waiting for next.
Lines 6–8Right button: step forward.
If the pressed button matches CORRECT[progress], we advance progress by one. When progress passes the end of the list (#CORRECT is its length), every button was pressed in order.
Lines 9–12Solved: open the door.
Turning CanCollide off lets the player walk through; the transparency change shows it opened. This is the win condition — the whole obby's final gate.
Lines 14–15Wrong button: reset.
Any wrong press sends progress back to 1, so the player must start the sequence over. One number is the entire memory of the puzzle.
Understand it
The puzzle is your first taste of game logic — code that isn't about motion or danger, but about rules. The whole puzzle is one number, progress, tracking how far through the order you are. Right presses move it forward; a wrong press snaps it back to 1. That idea — a small piece of state that remembers where you are in a process — runs every menu, quest, combo, and level-unlock in games. You wired it with the same instinct you've used since Stage 1: each button reports an event (Triggered), and one function decides what it means.
The publish-and-playtest is the closing of the loop, and it's worth sitting with. All course, you wrote VR code you couldn't run, trusting one pattern: guard it behind VREnabled, build the non-VR path so everyone can finish, and verify in the headset at the end. That discipline is exactly how real cross-platform games are made — a developer can't test every device every day, so they build for the common case and gate the special features cleanly. When you put on the headset and every feature works at once, that's not luck. It's the payoff of writing honest, guarded code from Stage 1.
Try this
Try this
Three short experiments. Predict before you run, then test your guess.
The order is Green → Red → Blue. Predict what happens if you press Green, Red, then Green again. Where does progress end up? Trace it by hand before testing — this is how you debug logic, by following the number.
The puzzle resets to 1 on any wrong press. Imagine a kinder version that just ignores wrong presses (stays where it is). Which makes a better final puzzle — punishing resets or forgiving ignores? There's no single right answer; argue for your game.
You've now built ten stages on one obby and one VRController. Look back at the tags you used — Climbable, Killer, Hidden, Boulder — and the buttons' sequence. What's the one habit underneath all of it? That habit is what you take to your next game.
Test your stage
- Press ▶ Play. A Press prompt appears at each button.
- Press Green → Red → Blue in order; the orange FinishDoor opens.
- Press them out of order; the sequence resets (the door stays shut).
- Walk through the open door, touch the Gold finish pad, reset, and confirm you respawn there (StageNumber 11).
- Your
VRControllercomfort-pass checklist (Step 4) is all ticked. - Your game is published and has a real link.
- The Play-in-VR portal sits on the
ExtensionPadwith your game's name. - In the headset: climb, fade, buzzes, reveal, danger sense, grab-and-ride, and ledges all work as you play start to finish.
- Design check. Play your whole obby once more, end to end. Does the difficulty rise fairly? Is every stage beatable on a laptop? Is every VR feature a delight, not a chore? Fix anything that isn't.
If it breaks
- No prompt appears at the buttons. ProximityPrompts only show within range; walk closer. Confirm the
PuzzlePanelscript is in ServerScriptService and the button names matchCORRECTexactly. - The door won't open even with the right order. Check the button names are spelled exactly as in
CORRECT, and thatFinishDooris named exactly that. Watch Output for the "solved" message to see if the logic ran. - The door opens on any presses. Your
CORRECTlist or theprogresschecks were changed — compare carefully against the script above. - Publishing is greyed out or asks me to sign in. You need to be signed into Studio with your Roblox account. A coach can help with account and privacy settings.
- A VR feature misbehaves in the headset. This is what the playtest is for. Note which one, reread that stage's
VRControllerblock, and tune its numbers (reach, range, strength). Finding and fixing these is real VR development.
This is the celebration, so protect time for it. The build and puzzle are quick; the publish and the headset playtest are the point. If you have a headset, this is the day to use it — pass it around so every camper plays their own obby in VR, even briefly. The look on their face when the climb they wrote blind actually lifts their hands is the whole course paying off.
The puzzle introduces logic/state; keep it light — one number, progress. The big teaching moment is the loop closing: name out loud that they wrote VR code blind for ten stages, trusted the VREnabled guard, and now it all works at once. That's professional cross-platform development in miniature.
If no headset is available, the course still completes fully on laptops — the published game is VR-ready for anyone who opens it in a headset later. Celebrate the shipped link as the artifact; the VR playtest can happen whenever a headset turns up.