gameover — wired automatically by the lives-watcher loop.Learning Goals 3 min
By the end of this lesson you will be able to:
- Create a lives variable that resets to 3 at the start of every game and decreases by 1 each time the player is hit, using change [lives v] by (-1).
- Wire three heart sprites on the Stage so each one hides itself once lives drops below its threshold, using <not <(lives) < (1)>> instead of a non-existent "greater than or equal" block.
- Add a short invulnerability window with a flag variable and wait (1) seconds, so one collision can't drain all three lives in the same frame.
Warm-Up — Boon's instant game over 7 min
Boon is making a flying-bee dodging game. The bee needs to avoid the swooping bird sprite. He writes the hit-detection like this:
when flag clicked
forever
if <touching [bird v] ?> then
broadcast (game over v)
end
end
It works — but the game is brutal. The bird grazes the bee for half a second and the player is immediately on the game-over screen. There's no recovery, no "I almost made it, let me try again", no pacing. Predict — what's the simplest thing Boon could add to make the game feel fair?
Reveal the answer
A lives counter. Instead of game-over on first hit, give the bee three hits before game-over. A variable called lives starts at 3, drops by 1 each collision, and only triggers game-over when it reaches 0. That's three chances, three near-misses, three "phew!" moments per game. Same engine, completely different feel.
And the visual icing: three heart sprites on the Stage that disappear one at a time, so the player can see their remaining lives at a glance.
By the end of this lesson, Boon's bee will survive two bird-touches and only game-over on the third — with three visible hearts ticking down to mark each loss.
New Concept — counter, hearts, invulnerability 15 min
The lives system has three moving parts. We'll meet each one in turn.
Part 1 — the counter variable
Open Variables → Make a Variable → name it lives → "For all sprites". Tick its checkbox so you can watch the number on the Stage while testing.
At flag click, reset to 3:
when flag clicked
set [lives v] to (3)
Every time the player is hit, lose one life:
if <touching [bird v] ?> then
change [lives v] by (-1)
end
When the counter hits zero, the game is over:
if <(lives) = (0)> then
broadcast (game over v)
end
game over.Part 2 — the three heart sprites
Make three heart sprites — call them Heart1, Heart2, Heart3. Place them in a row at the top-left of the Stage. Each heart watches lives and decides whether to show itself.
The rule for each heart: show me if lives is at least my number, otherwise hide. So Heart3 only shows when lives ≥ 3, Heart2 when lives ≥ 2, Heart1 when lives ≥ 1.
Here's where Scratch trips us up. There's a () < () reporter and a () > () reporter, but no "greater than or equal" block. We have to build "≥" ourselves using not. The trick: lives ≥ 3 is the same as not lives < 3. Wrap a <not <>> around the less-than:
when flag clicked
forever
if <not <(lives) < (3)>> then
show
else
hide
end
end
The script for Heart2 is identical except the number is 2. For Heart1, the number is 1. Three near-identical scripts, one per heart.
Part 3 — invulnerability
There's a sneaky problem. The collision check runs every frame — many times per second. One brush against the bird can drain all three lives in 50 milliseconds because the if-then fires 20+ times before the bee can move away.
The fix is an invulnerability window: after a hit, mark the player as untouchable for one second, then mark them touchable again. Make a variable called invulnerable (a flag — value yes or no):
when flag clicked
set [invulnerable v] to [no]
forever
if <<touching [bird v] ?> and <(invulnerable) = [no]>> then
change [lives v] by (-1)
set [invulnerable v] to [yes]
wait (1) seconds
set [invulnerable v] to [no]
end
end
Worked Example — Mei Ling's three-hit shark dodger 12 min
Mei Ling is building a fish-vs-shark game. The fish gets three hits before game-over, with three visible hearts and a one-second invulnerability window. Eight steps.
Step 1 — Variables setup
From Variables: Make a Variable → lives (for all sprites). Make a Variable → invulnerable (for all sprites). Tick both checkboxes so you can watch them during testing.
Step 2 — Reset on flag click
On the Stage, add:
when flag clicked
set [lives v] to (3)
set [invulnerable v] to [no]
Step 3 — Make three heart sprites
Choose a heart from the costume library (or paint one). Duplicate it twice. Name them Heart1, Heart2, Heart3. Drag them to the top-left of the Stage, side by side, with a small gap between each.
Step 4 — Wire Heart3 first
On Heart3:
when flag clicked
forever
if <not <(lives) < (3)>> then
show
else
hide
end
end
Step 5 — Copy to Heart2 and Heart1
Right-click the Heart3 script → duplicate. Drag the copy onto Heart2 in the sprite list. Open Heart2 and change the number 3 to 2. Do the same for Heart1 with the number 1.
Step 6 — Build the fish's collision script
On the fish sprite, add:
when flag clicked
forever
if <<touching [shark v] ?> and <(invulnerable) = [no]>> then
change [lives v] by (-1)
set [invulnerable v] to [yes]
wait (1) seconds
set [invulnerable v] to [no]
end
end
Step 7 — Game over when lives = 0
On the Stage (or the fish), add a second forever script:
when flag clicked
forever
if <(lives) = (0)> then
broadcast (game over v)
stop [this script v]
end
end
Step 8 — Test the whole thing
Click the flag. Three hearts visible. Steer the fish into the shark. One heart vanishes, the fish flashes invulnerable for one second (you can see invulnerable flip on the Stage). Bump again — second heart gone. Bump again — third heart gone, game-over broadcast fires.
The full assembled stack
when flag clicked
set [lives v] to (3)
set [invulnerable v] to [no]
when flag clicked
forever
if <<touching [shark v] ?> and <(invulnerable) = [no]>> then
change [lives v] by (-1)
set [invulnerable v] to [yes]
wait (1) seconds
set [invulnerable v] to [no]
end
end
when flag clicked
forever
if <(lives) = (0)> then
broadcast (game over v)
stop [this script v]
end
end
What you just built: the same lives system used in every classic arcade game from Donkey Kong to Mario. Counter, visible hearts, invulnerability window. Three pieces, all loosely coupled — change any one without breaking the others.
Try It Yourself — three lives drills 15 min
Goal: One sprite, one enemy, no hearts yet. Make a cat lose 1 life each time it touches a ball sprite. Start with 5 lives. When lives reach 0, the cat says Game over! for 2 seconds. No invulnerability — that's the next drill.
when flag clicked
set [lives v] to (5)
forever
if <touching [ball v] ?> then
change [lives v] by (-1)
wait (0.5) seconds
end
if <(lives) = (0)> then
say [Game over!] for (2) seconds
stop [all v]
end
end
Think: Without that wait, the cat would lose all 5 lives in less than a tenth of a second whenever it touched the ball — because the forever loop checks the collision dozens of times per frame.
Goal: Take the Easy cat. Add proper hearts. Three heart sprites at the top-left, each one hiding itself when lives drops below its threshold. Use the not <> trick to fake the missing "≥" operator.
when flag clicked
forever
if <not <(lives) < (2)>> then
show
else
hide
end
end
1, Heart3 uses 3. Change set [lives v] to (5) down to set [lives v] to (3) on the cat to match.Think: Why a separate sprite per heart instead of one heart sprite with three costumes? Because separate sprites give you free positioning and free animation — each heart can pop or fade away independently when it disappears.
Goal: Take the Medium project. Replace the crude wait (0.5) with the proper invulnerability flag pattern. Then add a visual cue: while invulnerable, the cat set [ghost v] effect to (50) (half-transparent). When invulnerability ends, set ghost back to 0.
when flag clicked
set [invulnerable v] to [no]
forever
if <<touching [ball v] ?> and <(invulnerable) = [no]>> then
change [lives v] by (-1)
set [invulnerable v] to [yes]
set [ghost v] effect to (50)
wait (1) seconds
set [invulnerable v] to [no]
set [ghost v] effect to (0)
end
end
Think: The ghost effect doesn't just look cool — it tells the player "you're safe right now, use this second to escape". Invulnerability windows in real games (Mario star, Zelda hit-flash) always come with a visual cue for exactly this reason.
Mini-Challenge — Priya's vanishing fourth heart 5 min
"The heart that's there one frame and gone the next"
Priya copied the heart script but accidentally pasted four hearts on the Stage. She names the fourth one Heart4 and gives it this script:
when flag clicked
forever
if <not <(lives) < (4)>> then
show
else
hide
end
end
Walk through the logic. Lives starts at 3 (from the Stage's setup script). The check asks: is lives at least 4?
Reveal one valid solution
Lives starts at 3. The check <not <(lives) < (4)>> means "is lives ≥ 4?". The answer is no — 3 is less than 4 — so the show branch never fires. Heart4 lives its whole life hidden.
There are two valid fixes depending on what Priya actually wanted:
- If she wanted four hearts: change the Stage's reset script to set [lives v] to (4). Now the player has four lives and Heart4 shows correctly.
- If she wanted three hearts: delete Heart4 — it was a mistake. The script is correct but unreachable.
The deeper lesson: the number of hearts must match the starting value of lives. If they disagree, either a heart never shows or you'll game-over with hearts still visible. Always change them together.
Recap 3 min
You built a three-piece lives system. A lives counter that resets to 3 at the start of each round and drops by 1 on each miss. Three heart sprites that watch the counter and hide themselves once lives drops below their threshold — using <not <(lives) < (N)>> to fake the missing ≥ operator. An invulnerable flag plus a wait (1) seconds that stops a single collision from draining all three lives at once. When lives reaches zero, the lives-watcher flips the state machine to gameover.
- Lives counter
- A variable (usually called
lives) that starts at a small whole number — typically 3 — and counts down by 1 on each player mistake. Game-over fires at zero. - Heart sprite
- A visual indicator sprite whose only job is to show or hide based on the value of the lives counter. One per life.
- Faking ≥ with not
- Scratch has () < () and () > () but no "greater than or equal". Build it as <not <(a) < (b)>> — "a is not less than b" means "a is at least b".
- Invulnerability window
- A short period after taking damage during which the player can't be hit again. Implemented with a flag variable (
yes/no) and a wait. Prevents single collisions from draining multiple lives. - Flag variable
- A variable used as an on/off switch — usually holding
yes/noortrue/false. Checked with () = () against the expected value.
Homework 2 min
The Three-Heart Asteroid Dodger. Build a small game where a rocket dodges three drifting asteroids on a black starfield Stage.
- Make a lives variable, set to 3 at flag click. Make an invulnerable flag, set to
noat flag click. - Make three heart sprites at the top-left of the Stage. Wire each one with the not <> trick so it hides when lives drops below its threshold.
- The rocket sprite moves with arrow keys (you've built this many times). It checks touching [Asteroid1 v] ? or touching [Asteroid2 v] ? or touching [Asteroid3 v] ? combined with the invulnerability check. On hit: lose 1 life, go invulnerable for 1 second, half-transparent ghost effect during the window.
- The three asteroids drift across the Stage on simple paths (you can glide or use move + edge bounce).
- When lives = 0, broadcast game over. (If you haven't built the L03-27 state machine, just have the rocket say [Game over!] and stop [all v].)
- Bonus: Add a "+1 life" power-up sprite that spawns occasionally. Touching it does change [lives v] by (1) — but cap it at 3 with a check, otherwise the heart-show logic will look weird with lives = 4.
Save as HW-L3-29-Asteroid-Dodger.sb3. Three asteroids, three hearts, one rocket, one rule: you get three brushes before game-over.
Bring back next class:
- The
.sb3file. - Your answer to: "The invulnerability wait is 1 second. What happens to the game feel if you change it to 0.1 seconds? What about 3 seconds? Try both and describe the difference."
Heads up for next class: SCR-L03-30 adds the other half of the arcade duo — a score counter that ticks up during play and a high-score that survives across games. You'll also meet a tiny use of lists to remember the last five scores.