Learning Goals 3 min
By the end of this Build lesson you will have:
- A complete Breakout clone with a mouse-controlled paddle, a bouncing ball, a 5×8 grid of clone-spawned bricks, random list-driven power-ups, particles + screen shake polish, a lives counter, and a title-and-game-over state machine — all in one project.
- A working game-state variable cycling through
title→playing→game-over→title, with backdrops and sprite visibility gated to the right state. - A shippable Scratch project you can upload to scratch.mit.edu and hand to a stranger to play without any explanation needed.
Warm-Up — what you already own 7 min
This is the final lesson of cluster F. You've spent five lessons (L04-32 through L04-35) building Breakout piece by piece. Today you stop building new things and start integrating. List everything you already have before you open Scratch:
- L04-32 — Brick Grids with Clones: a Brick sprite that uses nested repeat loops to spawn a 5×8 grid of itself with create clone of (myself v).
- L04-33 — Paddle Physics & Ball Bounce: mouse-tracking paddle pinned to the bottom of the Stage, and a ball that bounces off walls and off the paddle at an angle determined by where on the paddle it hit (centre = straight up, edge = sharp angle).
- L04-34 — Power-Ups Using Lists: the
power-upslist, the PowerUp sprite with three costumes, the random 1-in-5 drop on brick destroy, the apply-power-up paddle handler. - L04-35 — Particles & Shake: the Particle sprite that bursts on brick destroy, the change-and-undo paddle shake on big hits.
Predict puzzle. The big new idea today is a single global variable that decides what's happening on screen. Look at this Stage script:
when flag clicked
set [game-state v] to [title]
switch backdrop to (title-screen v)
when I receive (start-game v)
set [game-state v] to [playing]
set [score v] to (0)
set [lives v] to (3)
switch backdrop to (play-field v)
broadcast (spawn-bricks v)
when I receive (game-over v)
set [game-state v] to [game-over]
switch backdrop to (game-over v)
Where does the start-game broadcast come from, and what stops the ball from bouncing around the title screen?
Reveal the answer
start-game comes from a separate when [space v] key pressed hat — usually on the Stage or the title sprite — that fires only when game-state is currently title (we'll guard it with an if). What stops the ball from bouncing on the title screen is exactly that guard: every script that does things — the ball loop, the paddle loop, the brick spawn — starts with if (game-state) = [playing] then ... or only runs on a when I receive (start-game v) hat. Sprites that should appear only during play hide on flag and only show on the start-game broadcast.
That's the whole architecture of today's lesson. One variable, listened to from many sprites, deciding the entire shape of the game.
New Concept — the state machine + the wiring diagram 15 min
A Build lesson doesn't introduce one block — it introduces a structure. Today's structure is the state machine: one variable, a handful of named values it can hold, and every sprite gated by which value it is.
The three states
- title — Title backdrop showing "Press SPACE to play". Paddle hidden. Ball hidden. Bricks gone. Nothing moves.
- playing — Play-field backdrop. Paddle follows mouse, ball moves and bounces, bricks present, power-ups fall, score updates.
- game-over — Game-over backdrop showing "Final Score: NN — Press SPACE to play again". Paddle hidden, ball hidden.
The transitions: title + space → playing. playing + (lives = 0) → game-over. game-over + space → title (or directly back to playing). Three states, three arrows.
The event chain
Every script in the game is either:
- Hatted on a specific broadcast (start-game, game-over, brick-hit, etc.) and runs once when that broadcast fires.
- Hatted on when ⚑ clicked and starts a forever guarded by
if (game-state) = [playing] then ..., so the body only runs during play.
No script just "runs all the time" without checking state. That's the discipline.
The sprite roster
Six sprites total:
- Paddle — mouse-follow, holds shake handler and apply-power-up handler.
- Ball — bounces, deals damage to bricks, loses life on bottom-exit.
- Brick — original hidden; clones form the 5×8 grid. Each clone listens for ball-touch and runs brick-hit + maybe drops a power-up.
- PowerUp — clones fall, get caught by paddle, broadcast apply-power-up.
- Particle — clones burst on brick destroy.
- Title — listens for space, broadcasts start-game. Shows only during
titleandgame-overstates.
Plus three backdrops on the Stage: title-screen, play-field, game-over.
The brick grid as a state-aware spawner
You learned the 5×8 grid in L04-32. Today's twist: instead of spawning on flag-click, the Brick sprite spawns on spawn-bricks. That way you can re-spawn the grid every time the player starts a new game without restarting the whole project:
when I receive (spawn-bricks v)
delete this clone
hide
set [grid-y v] to (140)
repeat (5)
set [grid-x v] to (-175)
repeat (8)
go to x: (grid-x) y: (grid-y)
create clone of (myself v)
change [grid-x v] by (50)
end
change [grid-y v] by (-25)
end
Common Build mistakes
Worked Build — assembling the full Breakout in twelve steps 35 min
Open Scratch. You can start from your most polished L04-35 project (it already has paddle, ball, bricks, power-ups, particles, shake) and extend it. Or start from scratch and copy in scripts from each earlier lesson. Either way works.
Step 1 — Set up the three backdrops
Stage → Backdrops. Three backdrops: title-screen (big text "BREAKOUT" + "Press SPACE to play"), play-field (plain black or a starfield), game-over (text "Game Over" + "Press SPACE to play again"). Use the text tool in the paint editor — nothing fancy.
Step 2 — Create the global variables
Variables → Make a Variable. All For-all-sprites: game-state (string), score (number), lives (number). Show score and lives on the Stage; hide game-state (it's a debug-only variable).
Step 3 — Stage state-machine scripts
On the Stage, three hats:
when flag clicked
set [game-state v] to [title]
set [score v] to (0)
set [lives v] to (3)
switch backdrop to (title-screen v)
when key (space v) pressed
if <(game-state) = [title]> then
broadcast (start-game v)
end
if <(game-state) = [game-over]> then
broadcast (start-game v)
end
when I receive (start-game v)
set [game-state v] to [playing]
set [score v] to (0)
set [lives v] to (3)
switch backdrop to (play-field v)
broadcast (spawn-bricks v)
Step 4 — Paddle
From L04-33. Mouse-follow + state guard:
when flag clicked
hide
when I receive (start-game v)
show
go to x: (0) y: (-150)
forever
if <(game-state) = [playing]> then
set x to (mouse x)
end
end
Step 5 — Ball
From L04-33. Hidden on flag, hatched on start-game:
when flag clicked
hide
when I receive (start-game v)
go to x: (0) y: (-100)
point in direction (45)
show
forever
if <(game-state) = [playing]> then
move (6) steps
if on edge, bounce
if <touching (Paddle v) ?> then
point in direction ((90) + (((x position) - ([x position v] of [Paddle v])) * (3)))
change y by (10)
end
if <(y position) < (-175)> then
change [lives v] by (-1)
broadcast (shake v)
if <(lives) < (1)> then
broadcast (game-over v)
else
go to x: (0) y: (-100)
point in direction (45)
end
end
end
end
Step 6 — Brick spawner + brick behaviour
From L04-32. Spawn on spawn-bricks; ball-touch triggers brick-hit:
when flag clicked
hide
when I receive (spawn-bricks v)
delete this clone
hide
set [grid-y v] to (140)
repeat (5)
set [grid-x v] to (-175)
repeat (8)
go to x: (grid-x) y: (grid-y)
create clone of (myself v)
change [grid-x v] by (50)
end
change [grid-y v] by (-25)
end
when I start as a clone
show
forever
if <touching (Ball v) ?> then
broadcast (brick-hit v)
change [score v] by (10)
set [burst-x v] to (x position)
set [burst-y v] to (y position)
broadcast (burst v)
if <(pick random (1) to (5)) = (1)> then
set [drop-x v] to (x position)
set [drop-y v] to (y position)
broadcast (spawn-power-up v)
end
delete this clone
end
end
Step 7 — PowerUp
From L04-34. No changes needed — already spawn-on-broadcast and apply-on-touch. Just confirm power-up-type is For-this-sprite-only and the parent hides on flag.
Step 8 — Particle
From L04-35. Same structure — hide on flag, spawn on burst, clone behaviour fades and dies. No changes needed.
Step 9 — Game-over handler on the Stage
Add a fourth hat to the Stage:
when I receive (game-over v)
set [game-state v] to [game-over]
switch backdrop to (game-over v)
game-over immediately stops every state-guarded forever loop in the game — the ball freezes, the paddle stops tracking mouse, falling power-ups halt. Cheap, clean.Step 10 — Wipe leftover content on game-over
Power-up clones and brick clones that exist when the game ends will reappear in the next round if not cleaned up. Add a global broadcast on game-over and have each clone-bearing sprite delete its clones:
when I receive (game-over v)
delete this clone
Step 11 — Sound polish
Three sounds. Paddle gets a start sound (bonk v) in its when I receive (apply-power-up v). Brick gets a start sound (pop v) in its hit script (right next to broadcast burst). Stage gets a start sound (lose v) in when I receive (game-over v). Three sounds, three completely different feels of feedback.
Step 12 — Full end-to-end test, three times
Flag → title shows. Space → play starts, 40 bricks appear. Play until you destroy all bricks (you may need to play badly, since clearing 40 bricks usually takes 2–3 minutes). Catch some power-ups, drop the ball a few times. When lives = 0, game-over screen shows. Press space → back to play with fresh bricks, lives = 3, score = 0. If any step glitches, fix it and run the full chain again. This is the only way to know it works.
The full assembled stack — Stage
when flag clicked
set [game-state v] to [title]
set [score v] to (0)
set [lives v] to (3)
switch backdrop to (title-screen v)
when key (space v) pressed
if <<(game-state) = [title]> or <(game-state) = [game-over]>> then
broadcast (start-game v)
end
when I receive (start-game v)
set [game-state v] to [playing]
set [score v] to (0)
set [lives v] to (3)
switch backdrop to (play-field v)
broadcast (spawn-bricks v)
when I receive (game-over v)
set [game-state v] to [game-over]
switch backdrop to (game-over v)
start sound (lose v)
The full assembled stack — Ball
when flag clicked
hide
when I receive (start-game v)
go to x: (0) y: (-100)
point in direction (45)
show
forever
if <(game-state) = [playing]> then
move (6) steps
if on edge, bounce
if <touching (Paddle v) ?> then
point in direction ((90) + (((x position) - ([x position v] of [Paddle v])) * (3)))
change y by (10)
end
if <(y position) < (-175)> then
change [lives v] by (-1)
broadcast (shake v)
if <(lives) < (1)> then
broadcast (game-over v)
else
go to x: (0) y: (-100)
end
end
end
end
What you just built: a complete, shareable arcade game. Title → play → game-over → play again. Paddle physics, brick clones, power-ups, particles, screen shake, lives, score. Every piece was a previous lesson; today's lesson was the structure that lets them cooperate. Upload to scratch.mit.edu and ask friends to play. This is what a real Scratch project looks like.
Try It Yourself — three integration drills 15 min
Goal: Add a "win" state. When all 40 bricks are destroyed (i.e. score reaches 400), broadcast you-win and switch to a new backdrop you-win with "YOU CLEARED THE BOARD! Press SPACE to play again."
when I receive (brick-hit v)
if <(score) = (400)> then
broadcast (you-win v)
end
when I receive (you-win v)
set [game-state v] to [game-over]
switch backdrop to (you-win v)
start sound (cheer v)
game-over state for "you won" keeps the space-key-to-replay logic identical — no new state needed.Think: A win condition closes the loop. Without it, the game has only one ending — death. Adding a second ending (clearing the board) is a tiny script change with a huge effect on whether players keep trying.
Goal: Add a high-score variable that persists across rounds within one session. After each game ends, if the just-finished score is higher than the high-score, update high-score. Show both score and high-score on the Stage.
when flag clicked
set [high-score v] to (0)
when I receive (game-over v)
if <(score) > (high-score)> then
set [high-score v] to (score)
end
when I receive (you-win v)
if <(score) > (high-score)> then
set [high-score v] to (score)
end
Think: A persistent number across rounds gives players a long-term goal — "beat my own record". This is the difference between a one-shot game and one people keep returning to.
Goal: Add a difficulty curve. After every 100 score, the ball speeds up by 1 step per frame. The base speed is 6 (from the Ball script). Use a ball-speed variable that the ball reads each frame, and a "score milestone" handler that increases it.
when I receive (start-game v)
set [ball-speed v] to (6)
when I receive (brick-hit v)
if <((score) mod (100)) = (0)> then
change [ball-speed v] by (1)
end
Then in the Ball script, replace move (6) steps with move (ball-speed) steps.
Think: A difficulty curve is what stops a game from feeling repetitive after 30 seconds. Same bricks, same paddle, same physics — but each round gets a little harder, so the same skills feel sharper later. Almost every arcade game ever made does this.
Mini-Challenge — the game that won't restart 5 min
"Wei Han's stuck game-over"
Wei Han assembled the full Breakout. First game plays perfectly: bricks spawn, ball bounces, lives decrease, game-over screen appears. He presses space — and the game-over backdrop is replaced by the play-field backdrop, but no bricks appear and the ball doesn't move. Pressing space again does nothing. The game is stuck. Here are his relevant scripts:
when key (space v) pressed
if <(game-state) = [title]> then
broadcast (start-game v)
end
title state, not game-over.
when I receive (start-game v)
set [game-state v] to [playing]
switch backdrop to (play-field v)
broadcast (spawn-bricks v)
when I receive (spawn-bricks v)
hide
set [grid-y v] to (140)
repeat (5)
set [grid-x v] to (-175)
repeat (8)
go to x: (grid-x) y: (grid-y)
create clone of (myself v)
change [grid-x v] by (50)
end
change [grid-y v] by (-25)
end
Find three bugs and explain each one.
Reveal one valid solution
Three independent bugs all biting at once. That's classic Build-lesson chaos.
Bug 1 — Space key doesn't fire after game-over. The space handler only checks game-state = title. After the first game-over, game-state is game-over, not title, so pressing space does nothing — well, almost nothing. Actually Wei Han's claim that "space switches the backdrop" suggests another script is reacting to space, but the start-game broadcast itself never fires. Fix: add a second condition: if <<(game-state) = [title]> or <(game-state) = [game-over]>> then broadcast (start-game v).
Bug 2 — Score and lives don't reset. On flag-click, score = 0 and lives = 3. After one game, lives = 0. Restarting without resetting them means the new round starts with 0 lives, and the very first ball drop ends the game again instantly. Fix: set [score v] to (0) and set [lives v] to (3) at the start of the when I receive (start-game v) handler.
Bug 3 — Old brick clones still haunt the play-field. Wei Han's belief that "the bricks are destroyed" is wrong. Most of them are, but if the player dies before clearing the board (which is normal), the remaining live brick clones persist into the next game. Worse, when the new spawn-bricks runs, those old clones aren't wiped — and the new 40 clones spawn on top of them. Fix: restore delete this clone at the top of the spawn handler so every old clone wipes itself before the new grid is built.
when key (space v) pressed
if <<(game-state) = [title]> or <(game-state) = [game-over]>> then
broadcast (start-game v)
end
when I receive (start-game v)
set [game-state v] to [playing]
set [score v] to (0)
set [lives v] to (3)
switch backdrop to (play-field v)
broadcast (spawn-bricks v)
when I receive (spawn-bricks v)
delete this clone
hide
set [grid-y v] to (140)
repeat (5)
set [grid-x v] to (-175)
repeat (8)
go to x: (grid-x) y: (grid-y)
create clone of (myself v)
change [grid-x v] by (50)
end
change [grid-y v] by (-25)
end
The rule: in a Build, every restart path must do three things — accept the trigger, reset the variables, wipe the old state. Skip any one and the game looks "almost working" but breaks the moment a player tries to replay. The reset-and-wipe pattern is identical in every game you'll ever make.
Recap 3 min
You assembled a complete Breakout clone. Six sprites — Paddle, Ball, Brick, PowerUp, Particle, Title — plus the Stage's three backdrops and the game-state variable. The state machine flips between title, playing, game-over. The space key is the only player input outside of mouse-controlled paddle movement, and it advances between states. Every sprite is gated by the state — nothing moves on the title screen, nothing moves on the game-over screen — and every gameplay variable resets on start-game so replays are clean. The paddle physics from L04-33, the brick grid from L04-32, the power-up list from L04-34, and the particles + shake from L04-35 are all here, working together for the first time. You have a real arcade game. Upload it and let people play.
- Build lesson
- A lesson that assembles previous lessons rather than introducing new blocks. The hard part is structure and timing, not new syntax. Cluster F's Build is SCR-L04-36.
- State machine
- A pattern where one variable (game-state) holds one of a small set of named values (
title,playing,game-over), and every sprite checks that variable to decide whether to act. The skeleton of most games. - State guard
- An if inside a forever loop that wraps the body in
if (game-state) = [playing] then .... Lets one loop be "on" during play and "off" otherwise without restarting the script. - Wipe-before-respawn
- The pattern of running delete this clone at the top of any spawn handler so old clones from the previous game don't accumulate. Without it, replays leave invisible touchable junk on the Stage.
- Reset-on-start
- Every gameplay variable (score, lives, ball-speed) must be re-initialised in the start-game handler, not only on flag-click — otherwise the second game inherits the first game's end-state.
- End-to-end test
- Playing the entire game from flag to game-over to replay, three times in a row, to catch integration bugs. The only test that catches state-machine glitches.
Homework 2 min
The Share Drill. Take your assembled Breakout and prepare it for sharing.
- Save the project as
HW-L4-36-My-Breakout.sb3. - Open the Scratch website (scratch.mit.edu), sign in, and upload the project.
- Write a short project description: what the game is, how to play (mouse to move paddle, space to start), credits to the lessons or anyone who helped.
- Set the project to Shared.
- Send the link to two people — parent, sibling, classmate. Ask them to play it twice without you helping. Watch where they get stuck or which moments make them smile.
Bring back next class:
- The shareable Scratch URL.
- Your answer to: "What was the first thing your playtesters tried that you didn't expect? What's the smallest change you could make to handle it?"
- The
.sb3file as backup.
Heads up for next class: SCR-L04-37 opens cluster G — quiz and trivia games. We use lists in a new way: not as menus of choices, but as parallel arrays. One list of questions, one list of answers, walked through together. Your first project that's not a game in the arcade sense but still uses every list and broadcast technique you've learned. Bring your shared Breakout link — we'll spend the first 5 minutes of next class playing each other's clones.