Skip to main content

Stage 10: Puzzle Room + publish & play in VR

Course progressStage 10 of 10
~55 min
Before you start

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.

Build

a button-sequence puzzle room, a finish pad, and a Play-in-VR portal

Learn

how to track a sequence in code, how to publish a game, and how to playtest in VR

Ship

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.

New words
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 part

PuzzleFloor

Block
Open recipe
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 part

PuzzleWall_Left

Block
Open recipe
Size
1 × 12 × 24
Color
Dark stone grey
Material
Brick
Anchored
✓ Yes
Place
Left edge of PuzzleFloor
Build this part

PuzzleWall_Right

Block
Open recipe
Size
1 × 12 × 24
Color
Dark stone grey
Material
Brick
Anchored
✓ Yes
Place
Right edge of PuzzleFloor
Build this part

PuzzleWall_Back

Block
Open recipe
Size
24 × 12 × 1
Color
Dark stone grey
Material
Brick
Anchored
✓ Yes
Place
Back edge of PuzzleFloor
Build this part

FinishDoor

Block
Open recipe
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 part

Button_Green

Block
Open recipe
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 StageNumber attribute (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 part

ExtensionPad

Block
Open recipe
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 Climbable lifts 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) — Hidden tiles light near your hand.
  • Danger sense (Stage 7) — buzz grows as boulders near your head.
  • Grab & ride (Stage 8) — grip the SweepArm to 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.

In VR — the whole game wakes up

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.

Script anatomy

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

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

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

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

Learning beat

Try this

Three short experiments. Predict before you run, then test your guess.

Predict first

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.

Compare

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.

Connect

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 VRController comfort-pass checklist (Step 4) is all ticked.
  • Your game is published and has a real link.
  • The Play-in-VR portal sits on the ExtensionPad with 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 PuzzlePanel script is in ServerScriptService and the button names match CORRECT exactly.
  • The door won't open even with the right order. Check the button names are spelled exactly as in CORRECT, and that FinishDoor is named exactly that. Watch Output for the "solved" message to see if the logic ran.
  • The door opens on any presses. Your CORRECT list or the progress checks 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 VRController block, and tune its numbers (reach, range, strength). Finding and fixing these is real VR development.
Coach notes

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.