Learning Goals 3 min
By the end of this lesson you will be able to:
- Explain the scrolling trick: in a side-scroller, the player sprite never changes x — the world slides in the opposite direction, and your eyes are fooled into thinking the player moved.
- Use one world-x variable as the "camera" — change it when the player presses an arrow key, and every level sprite repositions itself based on its own tile-start-x minus world-x.
- Predict what happens to a platform's position on screen when world-x goes up, goes down, or stays still — and recognise that this is the same maths every scrolling game in the world uses.
Warm-Up — who's actually moving? 7 min
You've been on a KTM Komuter train and watched the platform slide backwards as the train pulls away. Or you've been sitting still on a parked train when the train next to you starts moving — and for a second, you swear you're moving in the opposite direction.
That illusion is the entire idea behind a scrolling platformer. The player on screen doesn't move; the world slides past them; your eyes (and your brain) decide the player is the one who moved.
when flag clicked
go to x: (0) y: (-100)
forever
if <key [right arrow v] pressed?> then
change x by (4)
end
end
If the level is wider than the Stage (say, four Stage-widths long), why is this approach a problem? Once the player walks off the right edge, what does the user see?
Reveal the answer
Once the player's x goes past 240 (the right edge of the Stage), Scratch clamps the sprite at the edge — exactly like the bouncing-cat warm-up from L2-06. The player visually freezes at the right wall, even though their x might be 800 or 8000. The user can't see anywhere past the original Stage. The world ends at the edge.
The fix is to never move the player's x at all. Keep them stuck in the centre. Move every other sprite in the opposite direction instead. The world becomes infinitely wide because the player never has to leave the Stage's centre.
That sounds backwards, and it is. It's also exactly how Mario, Sonic, Geometry Dash, and every side-scrolling game on Roblox does it under the hood. Today we meet the maths.
New Concept — the world-x camera 15 min
The whole idea is one variable, one rule, applied to every sprite.
One variable: world-x
Make a new variable, world-x, "for all sprites". It starts at 0. Think of it as the camera position: how far the player has "walked" into the level. When the player presses right, this variable increases. When they press left, it decreases. The player sprite itself never moves.
when flag clicked
set [world-x v] to (0)
forever
if <key [right arrow v] pressed?> then
change [world-x v] by (5)
end
if <key [left arrow v] pressed?> then
change [world-x v] by (-5)
end
end
One rule: every level sprite repositions itself
Every other sprite in the level — every platform, every tree, every coin — has a fixed "home" position in the level. We call that home position the tile-start-x. It's where the sprite would be if the camera were at 0.
Each frame, every level sprite computes its on-screen position with one tiny formula:
when flag clicked
forever
set x to ((tile-start-x) - (world-x))
end
Why minus, not plus?
Here's the bit that trips everyone up. When the player presses right (world-x goes up), the platforms should slide to the left. Because that's what your eye sees when you're walking forward — the world slides past you in the opposite direction.
- world-x = 0 → platform sits at its home x. Camera hasn't moved.
- world-x = +50 → player has "walked" 50 to the right. Platform is now at
home − 50— i.e. 50 to the left of where it started. - world-x = +200 → platform is 200 to the left of home. It might be off the Stage to the left, "behind" the player now.
The picture
when flag clicked
set [tile-start-x v] to (300)
forever
set x to ((tile-start-x) - (world-x))
end
What about the player?
The player sprite never moves on the x axis. It stays glued to x: 0 (or wherever you want the camera-centre to be). The player can still move on the y axis — jumps, gravity, ducking — but x is owned entirely by world-x, not by the player sprite's own position.
Worked Example — scroll three platforms past a fixed player 12 min
We're not building a full game today — just the illusion. Open Scratch.
set x to (tile-start-x) − (world-x) every frame — they slide left as world-x climbs.Step 1 — Make the variables
Variables panel. Make world-x for all sprites. Tick the show-on-Stage box so you can watch it tick up and down.
Step 2 — The player sprite
Use the default cat. Position at x: 0, y: −100. The cat will never move on the x axis again.
when flag clicked
go to x: (0) y: (-100)
set [world-x v] to (0)
forever
if <key [right arrow v] pressed?> then
change [world-x v] by (5)
end
if <key [left arrow v] pressed?> then
change [world-x v] by (-5)
end
end
Step 3 — Paint a platform sprite
New sprite, Paint icon. Draw a long brown rectangle. Name it Platform1. Place it anywhere — its starting position on Stage doesn't matter, because the script will set it every frame.
Step 4 — Give Platform1 its own tile-start-x
On Platform1, click Variables → Make a Variable → name it tile-start-x, and tick "for this sprite only". Crucial. Each platform needs its own.
Step 5 — Platform1's only script
when flag clicked
set [tile-start-x v] to (100)
set y to (-50)
forever
set x to ((tile-start-x) - (world-x))
end
Step 6 — Duplicate for Platform2 and Platform3
Right-click Platform1 → Duplicate → renames to Platform2. Open Platform2's script. Change tile-start-x to 400. Duplicate again → Platform3. Change its tile-start-x to 700.
Step 7 — Click the flag
Cat sits at x: 0, y: −100. Platform1 is at x: 100 (just to the right of the cat). Platform2 is at x: 400 (off the right edge — invisible). Platform3 at x: 700 (way off the right edge).
Step 8 — Hold the right arrow
world-x climbs: 5, 10, 15, 20, 25... Watch Platform1 slide left across the Stage. After world-x hits 100, Platform1 is at x: 0 — right under the cat. Keep going. Platform1 slides off the left edge. Platform2 slides into view from the right.
Step 9 — Press the left arrow
world-x ticks down. The platforms slide back to the right. You've just walked backwards through the level. The cat hasn't moved an inch.
What you just built: the camera system that runs every side-scroller. Mario doesn't move in Mario. The blocks move. Your brain does the rest.
The full per-platform script (10 blocks, the L3 cap)
when flag clicked
set [tile-start-x v] to (400)
set y to (-50)
show
forever
set x to ((tile-start-x) - (world-x))
if <(x position) > (260)> then
hide
else
show
end
end
Try It Yourself — three camera drills 15 min
Goal: Add a single tree sprite at tile-start-x = 200. It should scroll past in the background. Same formula as the platforms.
when flag clicked
set [tile-start-x v] to (200)
set y to (0)
forever
set x to ((tile-start-x) - (world-x))
end
Think: Trees, clouds, signs, coins — anything that lives in the level uses the exact same formula. Once you've written it on one sprite, you can paste it on every other sprite by changing only the tile-start-x number.
Goal: Add a "parallax" cloud. Clouds should scroll slower than the platforms — that's what makes them look further away. Use () / () from Operators to divide world-x by 2 before subtracting.
when flag clicked
set [tile-start-x v] to (150)
set y to (120)
forever
set x to ((tile-start-x) - ((world-x) / (2)))
end
Think: Dividing world-x by 2 means the cloud slides at half the speed of the platforms. Mario, Sonic, every 2D scroller does this for distant mountains and trees. It's called parallax, and it's two extra blocks.
Goal: Stop the player from walking left past the start of the level. world-x should never go below 0. Add a check after the left-arrow change.
when flag clicked
set [world-x v] to (0)
go to x: (0) y: (-100)
forever
if <key [right arrow v] pressed?> then
change [world-x v] by (5)
end
if <key [left arrow v] pressed?> then
change [world-x v] by (-5)
if <(world-x) < (0)> then
set [world-x v] to (0)
end
end
end
Think: "World edges" are just numerical limits on world-x. The left wall of the level is world-x = 0. If your level is 2000 pixels wide, the right wall is world-x = 2000. No walls needed — just a clamp.
Mini-Challenge — Mei Ling's runaway platforms 5 min
"My platforms are flying off twice as fast as my cat"
Mei Ling tried to build the scroll system but kept the old player-movement code by accident. Here's what she wrote:
when flag clicked
go to x: (0) y: (-100)
forever
if <key [right arrow v] pressed?> then
change x by (5)
change [world-x v] by (5)
end
end
What's the bug, and what should she keep — the change x by (5) or the change [world-x v] by (5)?
Reveal one valid solution
Mei Ling is moving the player and the world. The cat's own x climbs from 0 → 5 → 10 → 15 (sliding off the right edge), while at the same time every platform's screen position drops by 5 each frame (sliding off the left edge). They both move, but in opposite visual directions, and the user can't tell what's going on.
The fix: delete the change x by (5). The player stays at x: 0. Only world-x changes:
when flag clicked
go to x: (0) y: (-100)
forever
if <key [right arrow v] pressed?> then
change [world-x v] by (5)
end
end
Now only the world moves. The cat looks like it walked, because the scenery scrolled past. The whole trick is to resist the urge to move the player.
Recap 3 min
You met the camera trick that makes scrolling games possible. The player sprite never changes its own x — instead, a shared variable world-x represents "how far the player has walked into the level". Every level sprite (platforms, coins, trees) repositions itself each frame using one tiny formula: ((tile-start-x) − (world-x)). When world-x goes up, every platform slides left — fooling your eyes into thinking the player moved right. This is the same architecture used in every side-scroller ever written, from Mario to the latest indie platformer on Steam. Tomorrow we add gravity so the player can fall onto those platforms.
- Scrolling
- The technique of keeping the player visually centred and moving the world around them. Lets levels be much wider than the Stage.
- world-x
- The "camera" variable, shared across all sprites. Represents how far the player has walked into the level. Player presses right → world-x increases.
- tile-start-x
- A "for this sprite only" variable on each level sprite. Holds the sprite's home position — where it would be if the camera were at 0.
- Parallax
- Scrolling background sprites slower than foreground sprites, to fake depth. Just divide world-x by 2 (or 3, or 4) before subtracting.
- Camera
- The imaginary "viewer" that decides what part of the level is on screen. In Scratch, the camera is just the value of world-x.
Homework 2 min
Petronas-Towers Walk. Build a sideways-scrolling Kuala Lumpur skyline.
- Use the default cat as the player. Position at x: 0, y: −100. Cat never moves on x — only on world-x.
- Paint five building sprites. Two should be the Petronas Towers (tall silver), two should be smaller shop-lots, one should be a KL Tower with the ball on top.
- Give each building its own tile-start-x: 150, 400, 700, 1000, 1300 — spread them across the level.
- Every building uses set x to ((tile-start-x) − (world-x)) in a forever.
- Bonus: paint two clouds and scroll them at half speed using ((tile-start-x) − ((world-x) / (2))).
Save as HW-L3-38-KL-Skyline-Walk.sb3. Hold the right arrow — the cat strolls through the city as the buildings drift past.
Bring back next class:
- The
.sb3file. - Your answer to: "What's the smallest number you can change [world-x v] by and still feel like the cat is walking? What's the biggest before it looks like teleporting?"
Heads up for next class: SCR-L03-39 adds gravity. The cat won't just walk past the buildings — it'll fall until it lands on one. We do it with a single variable velocity-y that gets pulled down by 1 every frame.