paused state freezes everything mid-game — kuih hang in the air, the cat stops responding — and a PAUSED overlay appears. One more key-press sends everything back to play exactly where it left off.Learning Goals 3 min
By the end of this lesson you will be able to:
- Add a fourth value —
paused— to the state variable you built in L03-27, on top oftitle,play, andgame over. - Use a single when [p v] key pressed hat with a nested if <> then else to toggle between
playandpausedwithout breaking the other states. - Explain why every gated game script (everything wrapped in <(state) = [play]>) freezes automatically the moment
statechanges — no stop blocks needed.
Warm-Up — Aisha's broken pause button 7 min
Aisha is building a catch-the-durian game. She wants to press P mid-game to freeze everything so she can answer her mum's call, then press P again to unfreeze. She tries the obvious thing — a stop block on every sprite:
when [p v] key pressed
stop [other scripts in sprite v]
Click the flag mentally. She presses P. Everything stops. Good. Then she presses P again. Predict — what happens?
Reveal the answer
Nothing happens. Stop blocks only stop things. They don't remember what was running, so there's nothing to restart. To resume, Aisha would have to re-broadcast every start event on every sprite, manually, and hope nothing ends up in a half-finished state. It's a mess.
Today's lesson shows the trick real games use: keep one variable called state, gate every game script on it, and pausing becomes free. Pressing P just changes a word in a variable — and every gated script naturally freezes because their if check is suddenly false.
The hard part isn't writing the pause script. The hard part is having the right shape of game underneath. You built that shape in L03-27. Today we slot pause in.
New Concept — adding a fourth state 15 min
Quick recap from L03-27. You have a variable called state that holds one of three text values: title, play, or game over. Every game-action script — moving sprites, dropping durians, counting score — sits inside a forever loop with an if <> then gate on it:
when flag clicked
forever
if <(state) = [play]> then
move (10) steps
end
end
The big idea — change the state, freeze the game
If state stops being play for even one frame, the inside of every gated script is skipped. The forever loop is still looping — but every if-then is now false. The sprite doesn't move. The durian doesn't drop. The score doesn't tick. The whole game looks frozen, and yet no script was stopped.
That means you don't need stop blocks at all. You just need a new value for state. We'll call it paused.
Where to find the key hat
Open the Events palette. The hat you want is when [space v] key pressed. Click the dropdown and choose p instead of space. This script fires once each time the player taps P.
when [p v] key pressed
The toggle pattern
We want P to do two different things depending on where we are:
- If we're playing — pause. (Change state from
playtopaused.) - If we're paused — unpause. (Change state from
pausedtoplay.) - If we're on the title screen or game-over screen — do nothing. Pause shouldn't work outside of an active game.
That's a nested if-then-else. Read it slowly:
when [p v] key pressed
if <(state) = [play]> then
set [state v] to [paused]
show
else
if <(state) = [paused]> then
set [state v] to [play]
hide
end
end
Walk through it. State is play? The outer if fires — flip to paused and show the PAUSED sign. State is paused? Outer if is false, go to the else, inner if fires — flip back to play and hide the PAUSED sign. State is title or game over? Outer if false, inner if false, nothing happens. Exactly what we want.
The PAUSED indicator sprite
Make a new sprite using the text tool — type the word PAUSED in big bold letters, centred on a transparent square. This sprite has only two scripts:
when flag clicked
hide
It only appears when the pause toggle calls show on it. (In the worked example, we'll make the pause script live on this sprite so the show/hide calls work directly.)
Worked Example — pause-able durian catcher 12 min
Open your L03-27 project (or any small game with a state variable). We're going to slot pause in seven steps. The whole feature is about ten new blocks total.
state changes to paused. You only need to add the toggle hat.Step 1 — Confirm your state variable exists
Variables palette. You should already have a variable called state from L03-27. Tick its checkbox to show it on the Stage so you can watch the value change as you press keys.
Step 2 — Confirm your gates are in place
Click on each game sprite (basket, durian, score reporter). Every action script should look like the gated pattern: forever loop, if-then with <(state) = [play]>, action inside. If any script is ungated, gate it now — otherwise pause won't freeze it.
Step 3 — Create the PAUSED indicator sprite
Click the new sprite icon → Paint. Use the text tool, type PAUSED in large yellow letters with a black outline. Centre it. Name the sprite PausedSign.
Step 4 — Hide it at startup
On PausedSign, add:
when flag clicked
hide
Step 5 — Add the pause toggle hat
Still on PausedSign, add the key hat from Events: when [p v] key pressed.
Step 6 — Build the nested if-then-else under it
From Control: if <> then else. Diamond gets <(state) = [play]>. Top body gets set [state v] to [paused] and show. Inside the else, drop a second if <> then with <(state) = [paused]>, and inside that put set [state v] to [play] and hide.
Step 7 — Test it
Click the flag. Pick "Play" from the title screen (or however your L03-27 game starts). While the durian is dropping, press P. The PAUSED sign appears, the durian freezes mid-air, the basket stops responding to arrows. Press P again. The PAUSED sign disappears, the durian resumes falling, the basket moves again. Try pressing P on the title screen — nothing happens. That's the inner check protecting you.
The full assembled stack
when flag clicked
hide
when [p v] key pressed
if <(state) = [play]> then
set [state v] to [paused]
show
else
if <(state) = [paused]> then
set [state v] to [play]
hide
end
end
What you just built: the same pause system used in arcade classics like Pac-Man and modern games like Stardew Valley. The trick is the architecture, not the pause button. Once your scripts are gated on a state variable, pause is just one more value the variable can take.
Try It Yourself — three pause drills 15 min
Goal: One sprite, one variable. Make a fish that swims back and forth across the Stage, but freezes when you press P and resumes when you press P again. No title screen, no game over — just play and pause.
when flag clicked
set [state v] to [play]
forever
if <(state) = [play]> then
move (5) steps
if on edge, bounce
end
end
when [p v] key pressed
if <(state) = [play]> then
set [state v] to [paused]
else
set [state v] to [play]
end
Think: Why is the simple if-else safe here? Because there's no title or game over — the only two values are play and paused. The nested check from the lesson is only needed when more states exist.
Goal: Same fish, but now add a PAUSED text sprite that shows when paused and hides when playing. The fish script stays unchanged from the Easy task — only the PAUSED sprite is new.
when flag clicked
hide
when [p v] key pressed
if <(state) = [paused]> then
show
else
hide
end
Think: This sprite doesn't change the state — it just reads it and reacts. That's a different role from the fish, which is the one actually setting the state.
Goal: Take your L03-27 title-screen game. Add the full pause system from the worked example. Then add a small extra: while paused, the PAUSED sprite should slowly pulse — change size by (5) then wait, then change size by (-5) — but only while paused. As soon as you unpause, it stops pulsing.
when flag clicked
hide
forever
if <(state) = [paused]> then
change size by (5)
wait (0.3) seconds
change size by (-5)
wait (0.3) seconds
end
end
Think: The pulsing script is gated on paused, not play. Same pattern, different state. That's the power of gating — you can build "things that only happen while X" for any state, not just the play state.
Mini-Challenge — Hafiz's stuck-on-pause bug 5 min
"The game I can never resume"
Hafiz built pause for his catch game. It pauses fine. But once paused, pressing P again does nothing — the game stays frozen forever. He shows you his pause toggle:
when [p v] key pressed
if <(state) = [play]> then
set [state v] to [paused]
end
if <(state) = [paused]> then
set [state v] to [play]
end
Walk through it mentally with state starting at play. What happens on the first P? What about the second?
Reveal one valid solution
The two if-thens run back to back, not as alternatives. On the first P:
- State is
play→ first if fires → state becomespaused. - State is now
paused→ second if fires → state becomesplay.
So on the first press, the state ends up right back where it started — at play. The game never actually pauses. Hafiz thinks his pause is broken, but really it's pausing and unpausing in the same key press.
The fix is to use if-then-else so the two branches are mutually exclusive — only one runs per key press:
when [p v] key pressed
if <(state) = [play]> then
set [state v] to [paused]
else
if <(state) = [paused]> then
set [state v] to [play]
end
end
Almost the same blocks, totally different behaviour. The lesson: when two checks can flip the same variable, they must be in if-then-else, not stacked if-thens. Otherwise the second check sees the result of the first and undoes it.
Recap 3 min
You added a fourth state — paused — on top of title, play, and game over from L03-27. Pressing P swaps the value of state between play and paused. Every other script in the game is gated on <(state) = [play]>, so they all naturally freeze the moment the state changes — no stop blocks needed, no scripts to restart. A PAUSED indicator sprite shows and hides on the same key press. The whole feature is about ten blocks. The architecture from L03-27 did the heavy lifting.
- Pause state
- A fourth value of the state variable —
paused— that freezes all gated game scripts by making their if-checks false. The scripts keep looping; they just skip their bodies. - Toggle
- A pattern that flips a variable between two values each time it runs. The pause script is a state toggle — play becomes paused, paused becomes play.
- Nested if-then-else
- An if <> then else with another if-then placed inside its else branch. Lets you check several mutually exclusive conditions cleanly.
- Indicator sprite
- A sprite whose only job is to display a state visually — like the PAUSED text. It reads the state, doesn't change it.
- Gated script
- A script wrapped in if <(state) = [...]> then inside a forever loop. Only runs its body when the state matches. The core pattern that makes state machines work.
Homework 2 min
The Pause-able Pong. Build (or open your existing) two-paddle ping-pong project. Add a complete pause system.
- Add a state variable if it doesn't exist. Set it to
playat flag click. - Gate every action script — paddle movement, ball motion, score updates — inside if <(state) = [play]> then inside a forever loop.
- Add a PAUSED text sprite. Hide it at flag click.
- On the PAUSED sprite, add the nested toggle from the worked example. P flips play ↔ paused and shows/hides the sign.
- Bonus: Add a second key — R — that resets the state to
playfrom any state. This is useful when testing because you can un-stick the game at any moment.
Save as HW-L3-28-Pause-able-Pong.sb3. Test: start a rally, press P mid-rally (ball should freeze in mid-flight), press P again (rally continues), press R while paused (game un-pauses immediately).
Bring back next class:
- The
.sb3file. - Your answer to: "What would go wrong if you forgot to gate the ball's motion script and left it as a plain forever-move? Try it and describe what the game looks like during pause."
Heads up for next class: SCR-L03-29 adds a lives counter — three hearts on the Stage that vanish one by one as the player gets hit. When lives reaches zero, the state flips to game over automatically. We'll also add a brief invulnerability window so a single collision doesn't drain all three lives at once.