Stage 7: Rolling Rocks
Make sure you've finished Stage 6: Hidden Hazard Field.
a ramp with rolling rocks and cover
how moving obstacles create timing pressure
a dodge section that rewards smart movement

Preview the rolling-rock ramp with cover spots that create a sprint-hide-sprint rhythm.
Build this stage belowThe big idea
Stage 5's fireballs flew across the path. Stage 6's hazards hid in plain sight. Today's hazard — rolling boulders — comes down the path the player is on. You aren't dodging across danger anymore. You're racing up the same lane as the danger.
The new design lesson is cover gives the player a beat. Without cover, the player would have to dash from the bottom to the top while boulders rain down — almost no game ever shipped this works. With one cover spot in the middle, the long climb breaks into two short ones. The player can stop, watch the pattern, and dash when it's safe. That stop-and-dash rhythm is what every action game uses to make hard sections feel fair.
The cover is a design tool, not a Roblox feature. It's just a wide flat block. The thing that makes it special is where you place it — between the danger and the goal, in a spot the player can reach in a single dash.
Build it
Step 1 — Build the ramp, cover, and spawner
A ramp with a cover spot halfway up. Boulders roll down. The player dodges up.

Build this partRockRamp
WedgeOpen recipe
RockRamp
Wedge- Size
- 6 × 8 × 30
- Color
- Dark stone grey
- Material
- Slate
- Anchored
- ✓ Yes
- Place
- Right in front of the Stage 7 checkpoint, sloping up. The X (6) is the width, Y (8) is the rise, Z (30) is the length.
Wedges have a flat bottom and a sloped top. If the slope points the wrong way, change Orientation Y in Properties.
Build this partCoverBlock
BlockOpen recipe
CoverBlock
Block- Size
- 3 × 4 × 1
- Color
- Reddish brown
- Material
- Wood
- Anchored
- ✓ Yes
- Place
- Standing upright on the ramp, about halfway up, slightly off to one side so a player can duck behind it
The cover is the key design move. Without it, the ramp is a brutal dash. With it, the climb becomes 'sprint, hide, sprint.'
Build this partBoulderSpawner
BlockOpen recipe
BoulderSpawner
Block- Size
- 2 × 2 × 2
- Color
- Bright red
- Material
- Neon
- Anchored
- ✓ Yes
- Place
- At the very top of RockRamp, slightly above its surface
Bright red + Neon while testing so you can see where it is. Later you can set Transparency = 1 in Properties to hide it from players — the spawner is mechanical, not part of the level.
Step 2 — Add the script that rolls boulders
The script makes the spawner create a boulder every 2 seconds and tween it smoothly down the ramp. Right-click BoulderSpawner → Insert Object → Script. Delete the placeholder.
BoulderSpawner
The Script goes inside BoulderSpawner. The variables at the top are the tunable parts — see 'Tune it' below.
local spawner = script.Parent
local TweenService = game:GetService("TweenService")
local Debris = game:GetService("Debris")
-- Tune these to change how the rocks feel
local spawnInterval = 2 -- seconds between boulders
local rollSeconds = 3 -- how long a boulder takes to reach the bottom
local boulderSize = 3 -- stud diameter of each boulder
local rampDrop = -8 -- studs down (negative = down)
local rampRun = -30 -- studs forward (negative = away from spawner)
local function spawnBoulder()
local boulder = Instance.new("Part")
boulder.Shape = Enum.PartType.Ball
boulder.Size = Vector3.new(boulderSize, boulderSize, boulderSize)
boulder.Color = Color3.fromRGB(80, 60, 50)
boulder.Material = Enum.Material.Slate
boulder.Position = spawner.Position
boulder.Anchored = true
boulder.Touched:Connect(function(otherPart)
local character = otherPart.Parent
local humanoid = character:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid.Health = 0
end
end)
boulder.Parent = workspace
local destination = spawner.Position + Vector3.new(0, rampDrop, rampRun)
local info = TweenInfo.new(rollSeconds, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
local tween = TweenService:Create(boulder, info, { Position = destination })
tween:Play()
Debris:AddItem(boulder, rollSeconds + 1)
end
while true do
spawnBoulder()
wait(spawnInterval)
end
Press ▶ Play. A grey boulder spawns at the top of the ramp every 2 seconds and rolls smoothly down. Touch one and you respawn.
Tune it
The first five lines of the script are the variables you'll change most often. You can open the Script in Studio and tweak any of them:
spawnInterval = 2— how often a boulder spawns. Bigger = more time to dash.rollSeconds = 3— how long the boulder takes to roll down. Smaller = faster boulder.boulderSize = 3— bigger boulders are harder to dodge.rampDropandrampRun— match these to your ramp's height and length if you build a longer or steeper ramp.
Try a few different values and feel the difference.
Step 2 — Add the next checkpoint
Stage 8 checkpoint goes at the top of the ramp — the reward for surviving the climb.
2.1 Add another SpawnLocation
In Explorer, right-click Workspace → Insert Object → SpawnLocation.
2.2 Set its properties
- BrickColor → a new color.
- AllowTeamChangeOnTouch → checked.
- Neutral → unchecked.
- TeamColor → matches the BrickColor.
2.3 Tag it with its stage number
Same gesture as Stage 1. In the Attributes section of Properties, add a StageNumber attribute (number type) and set its value to 8.
2.4 Add a Team
- In Teams, insert a new Team named Stage 8.
- Uncheck AutoAssignable.
- Set TeamColor to match.
Drag the SpawnLocation onto the top of the ramp.
Understand it
The reason rolling boulders feel different from Stage 5's flying fireballs is the direction matters. A fireball crosses the player's path — they can stand still and let it pass. A boulder follows the player's lane — standing still doesn't help. Same kind of timing hazard, but now the player has to move through it. Game designers call this "lane-shared" danger, and it's the basic mechanic of every endless runner.
The cover spot is the smallest possible piece of level architecture. Roblox doesn't have a "cover" feature — we built it out of one regular block placed in one specific spot. Real action games are full of moments like this: a wall the player can crouch behind, a pillar that breaks line of sight. The idea of cover is what matters; the implementation is whatever part of the world you bend to that purpose.
The BoulderSpawner script has a row of tunable variables at the top (spawnInterval, rollSeconds, boulderSize). That's a real engineering move: the recipe for one boulder is the long part of the code, but the rhythm and feel live in a few short variables you can adjust without rewriting anything. Real game scripts are built that way on purpose — change a number, feel the difference, change it back.
Try this
Try this
Three short experiments. Predict before you run, then test your guess.
Delete the cover block and play through. Predict how it feels. Then put cover back and play again. How much harder was it without the cover? What does that tell you about how much work a single block can do in a level?
Try placing the cover block at the very bottom of the ramp instead of the middle. Does it still feel like cover? Why or why not? Where you place safety is as important as whether it exists.
Stage 8 swaps moving-down hazards for spinning-in-place hazards. Look at your ramp. What's harder to time: a danger that comes at you in a line, or a danger that spins in a circle? Why?
Test your stage
Before moving on:
- Press ▶ Play and start from the Stage 7 checkpoint.
- Wait behind cover and watch the boulder pattern.
- Climb the ramp without getting knocked back.
- Touch the Stage 8 checkpoint, reset, and confirm you respawn there.
- Design check. Does the boulder timing feel fair, or does the player have to get lucky?
If it breaks
- The BoulderSpawner doesn't roll any boulders. The Script is probably outside the spawner. In Explorer, the Script should be indented underneath BoulderSpawner. Also check Output (View → Output) for red errors — a typo in the script will be shown there.
- Boulders roll up the ramp instead of down. Your ramp is angled the opposite way from the script's assumption. Either rotate the ramp so its low end points away from BoulderSpawner, or open the Script and change
rampRun = -30torampRun = 30(flip the sign). - The boulders feel impossible to dodge. Open the Script and bump
spawnIntervalfrom2to3or4. Bigger number = more time between boulders = more time to react. You can also dropboulderSizeto make them smaller. - The cover spot is too small to hide behind. Resize it. Make it
[6, 4, 3]or whatever fits — the cover needs to be at least as tall as a Roblox character to actually block boulders. - My boulders go right through the cover. Cover block's CanCollide is unchecked. Click the cover, find CanCollide in Properties, check it.