Skip to main content

Stage 5: Fireball Cannon + player launcher

Course progressStage 5 of 10
~50 min
Before you start

Make sure you've finished Stage 4: KillBrick Path + dash & damage buzz. Your VRController should already hold the climb, comfort, edge-warning, and damage-buzz blocks.

Build

a cannon that launches the player across a huge gap

Learn

how to aim a launch with a part's direction, and how to fade the view for VR comfort

Ship

a giant arcing launch with a smooth fade-to-dark that keeps VR players from getting queasy

The big idea

This is the biggest move in the game: a cannon that fires you. Stage 2's jump pad bumped you up; Stage 4's dash nudged you forward. The cannon does both, huge — a long arcing flight across a gap too wide to cross any other way.

The trick is aiming. A cannon launches you the way its barrel points. Every part carries a forward direction in its CFrame — its LookVector — so if you rotate the barrel up and across the gap, barrel.CFrame.LookVector is the launch direction. Multiply it by a big power and you've got a cannonball — and the cannonball is you.

Now the VR problem. A small hop is fine in a headset. A massive launch is not: when the whole world rushes past your eyes but your inner ear feels nothing, your brain panics. That's motion sickness. The professional fix is to fade the view dark during the fast part and clear it when you land. Less rushing scenery, less queasiness. You'll build that fade as a smooth, speed-reactive overlay — real VR comfort engineering.

New words
CFrame
a part's position AND rotation together; it knows where the part is and which way it faces
LookVector
the forward direction stored in a CFrame — here, the way the barrel points
ScreenGui / Frame
2D UI drawn on the screen; a full-screen Frame is how we dim the view
BackgroundTransparency
how see-through a Frame is: 1 is invisible, 0 is solid — we slide it to fade
lerp (ease)
moving a value a little toward a target each frame, so changes feel smooth instead of snapping

Build it

Step 1 — Build the cannon

Three parts: a base, an aimable barrel, and a launch trigger at the mouth. Build the barrel as a Block so its front face matches the way it visually points.

Build this part

CannonPath

Block
Open recipe
Size
16 × 1 × 16
Color
Dark stone grey
Material
Slate
Anchored
✓ Yes
Place
Just past the Stage 5 pad — the launch platform
Build this part

CannonBase

Cylinder
Open recipe
Size
4 × 6 × 6
Color
Really black
Material
Metal
Anchored
✓ Yes
Place
Centered on the CannonPath

Just for looks — the base is the cannon's body.

Build this part

CannonBarrel

Block
Open recipe
Size
3 × 3 × 10
Color
Really black
Material
Metal
Anchored
✓ Yes
Place
Sitting on the CannonBase, the long side (10) pointing toward the gap

A Block, not a cylinder, so its FRONT FACE points where you'll launch. You'll rotate it in Step 2.

Build this part

CannonLaunch

Block
Open recipe
Size
4 × 1 × 4
Color
Bright yellow
Material
Neon
Anchored
✓ Yes
Place
Right at the mouth of the barrel, where the player steps to fire

This is the trigger. Yellow Neon says 'stand here.'

Step 2 — Aim the barrel and script the launch

2.1 Aim it

Select CannonBarrel and rotate it so its front face points up and across the gap — like a real cannon, maybe 30–45° above flat. The launch follows that front face, so aim is everything. You'll fine-tune after testing.

2.2 Script the launcher

Insert a server Script into CannonLaunch and type:

local trigger = script.Parent
local barrel = workspace:WaitForChild("CannonBarrel")
local LAUNCH_POWER = 180 -- this is a BIG launch
local onCooldown = {}

trigger.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
local root = character and character:FindFirstChild("HumanoidRootPart")
if not (humanoid and root) then return end
if onCooldown[character] then return end
onCooldown[character] = true

-- Launch the way the barrel's front face points.
root.AssemblyLinearVelocity = barrel.CFrame.LookVector * LAUNCH_POWER

task.wait(1.5)
onCooldown[character] = nil
end)

Press ▶ Play and step on the yellow pad. You should rocket out of the barrel in a long arc. If you fly the wrong way, re-aim the barrel (Step 2.1). If you fall short or overshoot, tune LAUNCH_POWER. This is fully testable on your laptop.

Step 3 — Place the Stage 6 checkpoint (the landing)

Build the landing platform where the cannon arc comes down, and put the next checkpoint on it.

  • Build a platform across the gap where you naturally land.
  • Insert a SpawnLocation on it. Size [6, 1, 6], anchored, a new color (try Teal). Check AllowTeamChangeOnTouch, uncheck Neutral, match TeamColor.
  • Add a StageNumber attribute (number) = 6.
  • Add a Team named Stage 6, matching TeamColor, AutoAssignable unchecked.

Adjust the barrel aim and LAUNCH_POWER together until the launch lands you cleanly on the new pad. Reset to confirm you respawn there.

Step 4 — Add the VR launch comfort fade

Open VRController. This block builds a full-screen black overlay once, then each frame eases it darker when you're moving fast and clear when you slow down. Paste it at the bottom:

-- ===== VR launch comfort fade (added in Stage 5) =====
local LAUNCH_SPEED = 80 -- speed where motion gets intense

local fadeGui = Instance.new("ScreenGui")
fadeGui.Name = "ComfortFade"
fadeGui.IgnoreGuiInset = true
fadeGui.ResetOnSpawn = false
fadeGui.Parent = player:WaitForChild("PlayerGui")

local blackout = Instance.new("Frame")
blackout.Size = UDim2.fromScale(1, 1)
blackout.BackgroundColor3 = Color3.new(0, 0, 0)
blackout.BackgroundTransparency = 1 -- start fully clear
blackout.Parent = fadeGui

RunService.RenderStepped:Connect(function()
if not VRService.VREnabled then return end
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root then return end

local speed = root.AssemblyLinearVelocity.Magnitude
local target = (speed > LAUNCH_SPEED) and 0.2 or 1 -- 0.2 = mostly dark, 1 = clear
local current = blackout.BackgroundTransparency
blackout.BackgroundTransparency = current + (target - current) * 0.1
end)

Press ▶ Play on your laptop. The overlay only activates inside the VREnabled check, so your desktop view is untouched and Output stays clean — today's pass. The fade does its real work in the headset.

In VR

Step on the launch pad in a headset and the world dims to near-black just as the cannon flings you, then clears smoothly as you land on the far platform. You still feel the thrill of the launch, but your eyes aren't flooded with rushing scenery — so your stomach stays calm. It's the difference between a launch players love and one that makes them take the headset off.

Script anatomy

How the comfort fade eases the view dark during fast motion

Build the overlay once, then react every frame. The easing line — nudge the current value a fraction toward the target — is a pattern you'll use any time you want smooth instead of snappy.

local LAUNCH_SPEED = 80

local fadeGui = Instance.new("ScreenGui")
fadeGui.IgnoreGuiInset = true
fadeGui.ResetOnSpawn = false
fadeGui.Parent = player:WaitForChild("PlayerGui")

local blackout = Instance.new("Frame")
blackout.Size = UDim2.fromScale(1, 1)
blackout.BackgroundColor3 = Color3.new(0, 0, 0)
blackout.BackgroundTransparency = 1
blackout.Parent = fadeGui

RunService.RenderStepped:Connect(function()
if not VRService.VREnabled then return end
local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if not root then return end

local speed = root.AssemblyLinearVelocity.Magnitude
local target = (speed > LAUNCH_SPEED) and 0.2 or 1
local current = blackout.BackgroundTransparency
blackout.BackgroundTransparency = current + (target - current) * 0.1
end)
  1. Lines 3–9Build the overlay one time.

    A ScreenGui holds a full-screen black Frame. ResetOnSpawn = false keeps it alive through respawns. IgnoreGuiInset makes it cover the whole screen. It starts at transparency 1 — completely invisible.

  2. Lines 15–16Measure how fast we're moving.

    AssemblyLinearVelocity.Magnitude turns the velocity vector into a single number: our speed. The cannon launch sends this way above LAUNCH_SPEED; walking is well below it.

  3. Line 17Pick a target darkness.

    Fast (above 80) -> target 0.2, mostly black. Slow -> target 1, fully clear. We never go to pure 0; a sliver of view left reduces panic better than total blackout.

  4. Lines 18–19Ease toward the target, don't snap.

    current + (target - current) * 0.1 moves the transparency 10% of the way to its goal each frame. Over several frames that's a smooth fade. Snapping straight to the target would itself be jarring — the easing IS the comfort.

Understand it

The launcher is the aiming lesson. AssemblyLinearVelocity is the same tool as the jump pad and the dash, but here the direction comes from the barrel itself: barrel.CFrame.LookVector. A CFrame bundles position and rotation, and LookVector reads the forward direction out of that rotation. So "aim the cannon" and "set the launch direction" are literally the same action — rotate the part, and the math follows. That's a glimpse of how real games point bullets, lasers, and cameras.

The comfort fade is the easing lesson, and it's subtle. We could have snapped the screen to black the instant speed crossed the line — but a snap is jarring, which defeats the purpose. Instead we move the transparency a fraction of the way to its target every frame (+ (target - current) * 0.1). That single line is one of the most useful patterns in all of game programming: smooth follow. You'll see it in camera movement, health bars, doors, and UI everywhere. Here it turns a comfort feature into one that itself feels comfortable.

Both lessons share the stage's theme: a big, exciting motion needs a soft touch around it. The launch is loud; the fade is gentle; together they're fun and kind to the player's body.

Try this

Learning beat

Try this

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

Predict first

LAUNCH_POWER is 180 — much bigger than the jump pad's 90. Predict what barrel.CFrame.LookVector * 180 does if the barrel is aimed nearly flat versus steeply up. Which aim flies farther? Which flies higher? Test both before you settle your landing platform.

Compare

In the fade, change the easing factor from 0.1 to 0.5, then to 0.02. One makes the fade snappy, one makes it sluggish. Which feels most like real comfort — and what does that teach you about choosing easing speeds for cameras and UI later?

Connect

You aimed a launch with LookVector. In Stage 7, boulders roll toward you. If you wanted a boulder to roll exactly down a ramp, whose LookVector would you use — the boulder's or the ramp's? Think it through; aiming things is about to come up again.

Test your stage

  • Press ▶ Play, step on the yellow CannonLaunch pad, and fly in a big arc out of the barrel.
  • Re-aim CannonBarrel and tune LAUNCH_POWER until you land cleanly on the Stage 6 platform.
  • The launch fires once per step (debounce), not repeatedly.
  • Touch the Stage 6 pad, reset, and confirm you respawn there.
  • Output is empty on a clean Play — no errors from the launcher or VRController.
  • Design check. Does the cannon look like it launches the way it fires? If the barrel points one way but you fly another, the aim and the look disagree — fix the rotation so they match. In VR, players trust what they see.

If it breaks

  • I launch the wrong direction. The barrel's front face sets the aim. Re-rotate CannonBarrel so its front points where you want to go, and remember it's a Block so the front face matches its long side.
  • barrel errors / is nil. The launcher does workspace:WaitForChild("CannonBarrel") — the part must be named exactly CannonBarrel and live in Workspace.
  • I overshoot or fall short. Tune LAUNCH_POWER and the barrel angle together. Flatter + stronger flies far; steeper flies high. Move the landing platform to match where you actually come down.
  • The launch repeats / I rocket forever. Debounce issue — confirm onCooldown[character] is set before task.wait(1.5) and cleared after.
  • On my laptop the screen never fades. Correct — VREnabled is false, so the fade loop is skipped. It's verified at the Stage 10 playtest.
Coach notes

This is the wow stage — campers will spend joyful minutes just launching themselves. Let them, then channel it into tuning: "make it land exactly on the pad" is a great, concrete goal that teaches aim + power as two separate dials.

The aiming concept (LookVector = front face) trips up campers who build the barrel as a cylinder — the cylinder's tube and its front face don't agree, and the launch looks "sideways." Insist on a Block barrel, or have them rotate until the launch matches the look.

The easing line (+ (target - current) * 0.1) is worth pausing on for the whole room — it's the most transferable idea in the stage. Show what 0.5 and 0.02 feel like (the Compare prompt). As always, the fade can't be seen on a laptop; the clean Play is the pass.