Learning Goals 3 min
By the end of this lesson you will be able to:
- Set up three backdrops (Title, Play, GameOver) on the Stage and switch between them automatically based on the value of a (state) variable.
- Write three small transition scripts — green-flag-to-title, any-key-to-play, lives-to-gameover — each using set [state v] to [...] together with broadcast (...).
- Gate every player and enemy script with if <(state) = [play]> then so the game only plays during the play phase — title screen and game-over screen sit perfectly still.
Warm-Up — the game that won't wait 7 min
Hafiz built a catch-the-durian game. He drew a beautiful title screen as a backdrop, then wrote this on the basket sprite:
when flag clicked
switch backdrop to [Title v]
forever
go to x: (mouse x) y: (-140)
end
Click the flag. Predict — does the player ever see the title screen?
Reveal the answer
Yes for half a frame, no for any useful time. The forever loop starts immediately. The basket starts chasing the mouse before the player has time to read the title. The game is effectively already in "play" mode. Hafiz never told his script "wait until the player says they're ready".
The missing piece is the (state) variable from last class. With it, Hafiz's basket script begins with if <(state) = [play]> then — and the basket politely waits on the title screen until the player presses a key. Today we build the whole three-state machine from scratch.
From now on, every project you build is a state machine. This is the lesson that turns your Scratch scripts from "demos" into "games".
New Concept — three backdrops, one variable, one broadcast 12 min
Last class we drew state diagrams on paper. Today we wire them up. A three-state machine needs three things on the Stage and three trigger scripts.
Three backdrops on the Stage
The Stage holds the scenery. Add three backdrops:
- Title — looks like a poster. Game name, "Press any key to start", maybe a screenshot.
- Play — the actual playing field. Background art, but no instructional text.
- GameOver — usually a slightly darker version of Play with "GAME OVER" big in the middle and "Score: ___" under it.
Switching backdrops is one block from Looks: switch backdrop to [Title v]. We'll wire it to the state variable so the backdrop follows the state automatically.
One state variable
Make a variable called state, scope For all sprites. Untick its Stage checkbox. Its value will be one of three words: "title", "play", "gameover".
when flag clicked
set [state v] to [title]
switch backdrop to [Title v]
One broadcast to start play
When the player presses a key on the title screen, we do three things in one script: change state to "play", switch backdrop to Play, and broadcast (start play v). The broadcast is the "go!" signal — any sprite that wants to initialise itself at the start of a round (reset score to 0, reset position, etc) listens for when I receive (start play v).
when [any v] key pressed
if <(state) = [title]> then
set [state v] to [play]
switch backdrop to [Play v]
broadcast (start play v)
end
Game over from inside the game
The third transition fires from inside the game itself — usually when a variable like lives drops to 0. It lives on whichever sprite is in charge of tracking the losing condition.
when flag clicked
forever
if <<(state) = [play]> and <(lives) = (0)>> then
set [state v] to [gameover]
switch backdrop to [GameOver v]
broadcast (game over v)
end
end
Worked Project — build the three-state shell 15 min
Open Scratch. Delete the cat. Paint three backdrops on the Stage — Title, Play, GameOver — or borrow from the backdrop library. Add two sprites: the Cat (our player) and any one Library sprite as a stand-in enemy. We're going to build the state shell only — no real gameplay yet, just the wiring.
Step 1 — Make the variables
From Variables, make:
state— For all sprites. Untick its Stage checkbox.lives— For all sprites. Leave its Stage checkbox ticked.
Step 2 — Stage script (reset to title)
Click the Stage thumbnail. Add this script to the Stage itself:
when flag clicked
set [state v] to [title]
switch backdrop to [Title v]
Step 3 — Stage script (any-key starts play)
Still on the Stage. Add the title → play trigger:
when [any v] key pressed
if <(state) = [title]> then
set [state v] to [play]
switch backdrop to [Play v]
broadcast (start play v)
end
Step 4 — Stage script (death watch)
Still on the Stage:
when flag clicked
forever
if <<(state) = [play]> and <(lives) = (0)>> then
set [state v] to [gameover]
switch backdrop to [GameOver v]
broadcast (game over v)
end
end
Step 5 — Cat: initialise on start play
Click the Cat sprite. Add the round-start script — this fires whenever a new play round begins, including the first one:
when I receive (start play v)
set [lives v] to (3)
go to x: (0) y: (0)
show
Step 6 — Cat: gated movement
The cat's movement loop runs forever, but only acts during play:
when flag clicked
forever
if <(state) = [play]> then
if <key [right arrow v] pressed?> then
change x by (5)
end
if <key [left arrow v] pressed?> then
change x by (-5)
end
end
end
Step 7 — Enemy: gated chase
Click your enemy sprite. Give it a gated chase script:
when flag clicked
forever
if <(state) = [play]> then
point towards (Cat v)
move (3) steps
if <touching (Cat v) ?> then
change [lives v] by (-1)
go to x: (200) y: (150)
end
end
end
Step 8 — Click the flag and walk through the loop
You should see:
- Title backdrop appears. Cat is somewhere on screen but doesn't move when you press arrows. Enemy stands still.
- Press any key. Backdrop switches to Play. Cat moves with arrow keys. Enemy chases.
- Get touched three times. The instant
liveshits 0, backdrop flips to GameOver. Everything freezes. - Press the flag to start again — back to title.
That's a full state machine. Three phases, three transitions, all the gameplay properly gated.
What you just built: the skeleton that every game you make for the rest of Level 3 starts with. Whatever gameplay you add — shooting, jumping, collecting, racing — slots into the gated forever loops. The state shell stays the same.
Try It Yourself — three add-ons 10 min
Goal: On the GameOver backdrop, make the cat say [Game Over!] for (2) seconds when the round ends. Use the game over broadcast we already created.
when I receive (game over v)
say [Game Over!] for (2) seconds
Think: Why doesn't this need a state gate? Because when I receive (...) already only fires when the broadcast goes out — and the broadcast only goes out when state flips to gameover. The state check is "built in".
Goal: Add a score variable. Make the cat earn 1 point every time it touches the enemy (instead of losing a life — temporarily, just to test scoring). Reset score to 0 on start play so each new round starts fresh.
when I receive (start play v)
set [score v] to (0)
set [lives v] to (3)
go to x: (0) y: (0)
show
Think: Why reset on start play and not on green flag? Because green flag goes to title — but a player might play five rounds in one session, and each new round needs a fresh score. The reset has to fire at the start of play, not at the start of the program.
Goal: Add a "press space to play again" feature. On the GameOver screen, pressing space should send the game back to play (not title) and start a fresh round.
when [space v] key pressed
if <(state) = [gameover]> then
set [state v] to [play]
switch backdrop to [Play v]
broadcast (start play v)
end
Think: Notice you didn't have to rewrite a single gameplay script to add this. That's the magic of state machines — every new transition is just one little trigger script.
Mini-Challenge — Daniel's ghostly cat 5 min
"The cat that moves on the title screen"
Daniel built the three-state shell, but his cat keeps walking on the title screen — even before the player has started. He's sure he wrote the state check. Here's his cat's movement script:
when flag clicked
if <(state) = [play]> then
forever
if <key [right arrow v] pressed?> then
change x by (5)
end
end
end
Click the flag mentally. Trace the script line by line. What's the order of events, and why does the state check fail?
Reveal one valid solution
The if <> then is checked once, the instant green flag is clicked. At that exact moment, the Stage's reset script has not yet set state to "title" — Scratch runs all the green-flag scripts in some order, and Daniel's cat script might run before the Stage's reset. So state is empty (""), which is not equal to "play", and the if-then's body never runs. The forever inside it never starts.
But wait — Daniel says the cat does move on the title screen. That's even more suspicious. Reading carefully, the script Daniel showed us wouldn't let the cat move on the title screen — it would never let the cat move at all. So Daniel probably has a second movement script he forgot about (the one from before he added state).
The fix is two-part: (a) put the state check inside the forever, not outside, so it's re-checked every frame; and (b) delete any old un-gated movement scripts.
when flag clicked
forever
if <(state) = [play]> then
if <key [right arrow v] pressed?> then
change x by (5)
end
end
end
Lesson: The state gate goes inside the forever, not around it. Outside-the-forever gating is a one-shot check that happens before state is even set. Inside-the-forever gating is checked every frame — exactly what we want.
Recap 3 min
You shipped your first state machine. Three backdrops on the Stage. One state variable holding the word "title", "play", or "gameover". Three transition scripts: green-flag-resets-to-title, any-key-starts-play, lives-zero-triggers-gameover. Every sprite's main loop is gated on if <(state) = [play]> then so the cat and the enemies only move during play. Every fresh-round setup (score, lives, positions) listens for when I receive (start play v) instead of green flag, because a single session has many rounds but only one flag click. From now on, every Scratch game you build sits inside this shell. Add new sprites, add new gameplay, but always inside the gated forever loops. The shell stays the same; the game on top of it grows.
- Backdrop
- The Stage's costume. Most state-machine games have one backdrop per phase, and switch backdrops in lockstep with the state variable.
- Broadcast
- A message sent from one script that any number of other scripts can listen for with when I receive (...). The
start playandgame overbroadcasts in this lesson are how we trigger "do this now" without polling. - Transition trigger
- A small script whose only job is to flip the state and (usually) broadcast a corresponding message. Each transition arrow on your state diagram needs one trigger script.
- Gating loop
- A forever loop whose body starts with if <(state) = [play]> then. The loop spins always; the body only acts during the right phase.
- Round-start script
- A when I receive (start play v) script that resets the per-round state (score, lives, positions). Different from a green-flag script, which only fires once per program start.
- Death watch
- A gated forever loop on the Stage that checks "are we in play AND have lives hit zero" and, if so, fires the play → gameover transition.
Homework 2 min
Wrap your favourite project in a state machine. Pick any project you've made earlier in Level 3 — Falling Stars, your list demo, anything. Add the title → play → gameover shell from this lesson.
- Paint or pick three backdrops: Title, Play, GameOver. The Title should show the project's name and "Press any key to start".
- Add the
statevariable (For all sprites, hidden) and the three Stage scripts: reset-to-title, any-key-starts-play, death-watch. - Gate every existing forever loop in the project with if <(state) = [play]> then. Test that nothing moves on the title screen.
- Decide your own game-over condition. Lives = 0? Timer hits 30 seconds? Score reaches 50? Whatever it is, wire it into the death watch.
Save as HW-L3-27-State-Wrap.sb3.
Bring back next class:
- The
.sb3file. - Your answer to: "How many scripts in your project did you have to gate? Which one did you nearly forget?"
Heads up for next class: SCR-L03-28 adds the fourth state — paused. We'll wire a P-key toggle that pauses and resumes mid-round without losing score or lives. The exact toggle pattern we previewed in last class's concept.