Stage 8: Eat or Be Eaten
Keep your Scratch project tab open all week. Open in a new tab so you don’t leave the course.
a second clone-behavior script that detects touching and decides who eats whom
how two sprites finally talk through collision and broadcast
the climactic moment — the game becomes a real game
Show the room — this is the moment the whole project clicks together:
- Click the Fish sprite. Show the EXISTING when I start as a clone script from Stage 7. "That one handles motion. We add a SECOND script that handles collision."
- Drag in another when I start as a clone block somewhere blank in the code area.
- Add wait until (touching Player) and (playerAlive = 1).
- Add if/else (enemySize < playerSize) then:
- In if (smaller enemy = food):
start sound chomp,change playerSize by (enemySize / 10),change fishEaten by 1,change score by (round enemySize),delete this clone. - In else (bigger enemy = danger):
broadcast playerEaten.
- In if (smaller enemy = food):
- Click the green flag. Move the player into a small enemy. Watch it disappear, score goes up, player grows. Then move into a big one. Lose path runs.
That moment of player-growth-from-eating is the whole game becoming real.
The big idea
Today the swarm and the player finally talk to each other.
For three stages, the Player Fish has been swimming alone. The enemy swarm has been gliding past it. Neither one cares about the other. Today we change that with collision detection — Scratch's way of asking "is sprite A touching sprite B right now?"
When a clone touches the Player, two things might happen:
clone touches Player
│
▼
compare sizes
│
├─── clone is SMALLER ─→ player eats it (chomp, grow, score)
│
└─── clone is BIGGER ─ → player loses (broadcast playerEaten)
The pattern is if/else: one branch for food, one branch for danger. Same touch, two completely different outcomes — driven by which sprite is bigger.
The new Scratch trick is that a clone can have MULTIPLE when I start as a clone scripts. They all run when the clone is born, in parallel. Stage 7's script handled motion (random spawn, glide, delete). Today's script handles collision (wait, compare, respond). One clone, two scripts running side by side.
When the player eats a smaller enemy, the script does four things at once:
- Plays the Chomp sound (audio feedback)
- Grows the player by
enemySize / 10(eating math) - Increments
fishEatenby 1 (stat tracking) - Adds to
scoreby the size of the meal (bigger meals = more points)
Then deletes the clone (it's been eaten).
When the player gets eaten by a bigger fish, the script broadcasts playerEaten — the message your Stage 4 lose handler is already listening for.
- collision detection
- checking whether two sprites are touching
- wait until
- a Control block that pauses the script until a condition is true
- touching
- a Sensing block that asks 'am I overlapping with that sprite?'
- if/else
- branches the code into two paths based on a condition
- round
- an Operators block that rounds a number to the nearest whole number
Stage 7 should be done — clones spawn with random costumes, colors, sizes, directions, and glide across the screen.
Build it
Step 1 — Add a second when-I-start-as-a-clone script
In the Fish sprite's code area, drag a FRESH when I start as a clone block somewhere blank — not connected to Stage 7's motion script.
Clones can run multiple when I start as a clone scripts in parallel. This new one will handle collision.
Step 2 — Wait until touching the player
The clone needs to pause until it actually bumps into the Player. We use wait until.
Drag wait until (<empty>) from Control under your new event block.
Now we build the condition. We want: "touching the Player AND the player is still alive."
From Operators, drag <empty> and <empty>.
Inside the LEFT slot of and: drag touching (Player) from Sensing. Pick Player from the dropdown.
Inside the RIGHT slot of and: drag <empty> = <empty> from Operators. On the left of the equals, drag playerAlive from Variables. On the right, type 1.
So the wait-until block now reads: wait until (touching (Player)?) and (playerAlive = 1).
The playerAlive = 1 check matters because after the player dies, the dead fish is still on stage briefly (the lose animation in Stage 4 takes 100 frames). Without that check, a clone could still try to "eat" the dead player — which would be weird.
Step 3 — Add the if/else size compare
Drag an if/else block under the wait-until.
Inside the diamond, build enemySize < playerSize:
- From Operators, drag the
<(less than) block. - On the left, drag enemySize from Variables.
- On the right, drag playerSize from Variables.
So the if-block reads: "if the clone is smaller than the player, then..."
Step 4 — Fill in the IF branch (the clone is food)
The IF branch runs when the clone is smaller than the player. The player eats it.
Inside the if body, add these blocks in order:
Collision script
when I start as a clone wait until <<touching [Player v] ?> and <(playerAlive) = (1)>> if <(enemySize) < (playerSize)> then start sound [chomp v] change [playerSize v] by ((enemySize) / (10)) change [fishEaten v] by (1) change [score v] by (round (enemySize)) delete this clone else broadcast [playerEaten v] end
How to build each:
- start sound (chomp) — Sound block. Pick chomp from the dropdown (you added it to the Fish sprite in Stage 5).
- change playerSize by (enemySize / 10) — drag the change block from Variables. Set the dropdown to playerSize. For the value, drag the
/(divide) Operators block. On the left of the divide, drop enemySize. On the right, type 10. - change fishEaten by (1) — straightforward.
- change score by (round (enemySize)) — change block on
score. For the value, drag round (<empty>) from Operators. Inside round, drop enemySize. (Round makes sure the score is a whole number even if enemySize has decimals.) - delete this clone — the clone has been eaten, remove it.
Step 5 — Fill in the ELSE branch (the clone is too big)
The ELSE branch runs when the clone is bigger than the player. The player gets eaten.
Inside the else body, add just one block:
broadcast (playerEaten)
Choose playerEaten from the dropdown. (If it doesn't exist yet, choose New message and type playerEaten.)
This broadcast triggers the LOSE handler you built in Stage 4. The player rotates, plays the Bubbles sound, pixelates, and disappears.
We don't delete this clone — it stays on stage as evidence of who got the player. Stage 4's stop other scripts in sprite will handle cleanup on the Player side; the clone keeps gliding until its motion script's delete this clone runs naturally.
Step 6 — Test the full game loop
Click the green flag. Play!
- Move your tiny Player around with the arrow keys.
- When you bump into a smaller clone, you should hear chomp, see the score go up, fishEaten increment, and your fish visibly grow.
- When you bump into a bigger clone, the Bubbles sound plays, the fish rotates, pixelates, and disappears. (That's the Stage 4 lose chain firing.)
- If you eat enough small ones and
playerSizecrosses100, the WIN chain from Stage 4 fires (Party Hat, Eggs sound, ghost fade).
You should now have a fully playable game.
Save your project. You just shipped real software.
Understand it
The most important idea today is that a single clone can run multiple when I start as a clone scripts at once. Stage 7's motion script and Stage 8's collision script BOTH run when each clone is born. They live in parallel — neither knows the other exists. The motion script handles "where the clone goes." The collision script handles "what happens if it bumps into the player." Two jobs, two scripts.
The reason we wait for (touching Player) and (playerAlive = 1) rather than just (touching Player) is defensive code. When the player loses (Stage 4), there's a 100-frame pixelate animation before the fish hides. During that animation, the dead fish is still technically on stage. Without the playerAlive = 1 check, a clone could touch the dying fish and trigger another playerEaten broadcast — which would re-fire the lose chain and look very weird. The check skips touching when the game is over.
The enemySize / 10 for growth is a critical tuning number. Without the divide-by-10, eating a size-50 enemy would jump the player's size from 15 to 65 — almost a win in one bite. Dividing by 10 keeps growth gradual: that same size-50 enemy adds 5 to the player's size. The player has to eat many small enemies to grow significantly. Small bites, real climb is the design rule.
The round enemySize for score is small but matters. enemySize is picked from pick random 5 to (playerSize + 20), which sometimes gives decimals like 23.7. Score is displayed as a whole number — without round, the score would show messy decimals like 23.7148 + 41.3209. Rounding keeps the display clean.
The else branch only broadcasts — no other cleanup. That's intentional. The Player's Stage 4 lose handler does everything: stop other scripts, play Bubbles, pixelate, broadcast gameover, hide. Centralizing the lose logic on the Player means the Fish doesn't need to know what "losing" looks like. Each sprite does what it knows; broadcast is the bridge.
The whole pattern — wait until touching → compare sizes → if/else → broadcast on bad outcome — is the same one used in every "eat-or-be-eaten" game ever made. Pac-Man uses it (with power pellets flipping who eats whom). Agar.io uses it. You just built a slice of the genre.
Try this
Try this
Three short experiments. Predict before you run, then test your guess.
Remove the and (playerAlive = 1) from the wait-until condition. Predict what happens after the player loses (a clone touches the dying fish). Try it. What broke? Put it back.
Change change playerSize by (enemySize / 10) to change playerSize by enemySize (no divide). Click the green flag. How many enemies do you need to eat to reach playerSize > 100? Is the game still fun, or is it solved in one bite?
Stage 9 adds a backdrop, music, and a timer that tracks how long the game lasts. Look at your collision script. What single variable does your collision script update most often that the timer or stats screen might want to read?
Test your stage
- Touching a smaller clone plays the chomp sound, makes the clone disappear, and grows the player.
- Touching a bigger clone triggers the LOSE chain from Stage 4 (Bubbles, rotated fish, pixelate fade).
- The fishEaten readout on stage goes up each time you eat.
- The score readout goes up each time you eat (by roughly the enemy's size).
- Eating enough small enemies grows
playerSizepast 100, which triggers the WIN chain (Party Hat, Eggs). - You can play a full round end-to-end (win OR lose) without anything crashing.
- Your project is saved.
- Design check. Play three rounds in a row. Does the game feel fair? Are there enough small enemies to grow on without getting eaten by big ones?
If it breaks
- Touching a small clone does nothing. Three suspects. First, is your
wait untilwaiting ontouching (Player)(capital P matters)? Second, isenemySize < playerSizethe right direction (smaller enemy, less-than)? Third, is the if/else's body block-set actually filled in (not empty)? - Touching a big clone does nothing. The else branch is empty, or the broadcast (playerEaten) dropdown points at the wrong message. Confirm the dropdown says
playerEatenexactly (camelCase, no space). - The chomp sound doesn't play. Did you add Chomp to the Fish sprite's Sounds tab in Stage 5? It needs to be on the Fish, not the Player.
- Player gets eaten but never dies. The Stage 4 lose chain isn't catching the broadcast. Check that the broadcast name in this stage (
playerEaten) matches exactly what Stage 4'swhen I receivelistens for. Same camelCase spelling on both sides. - Player size jumps wildly when eating. The
/10divide is missing or the value is different. Drag the divide operator back in and make sure both slots are filled (enemySizeon left,10on right). - Score updates with messy decimals. The round block is missing around
enemySizein thechange score byline. Addroundto keep the score whole. - Game keeps "eating" after I lose. The
and (playerAlive = 1)check is missing from the wait-until. Add it.
This is the climactic stage. The whole project comes together. Plan to celebrate the moment when each kid eats their first small enemy and visually grows. That growth is the "wow" of the entire course.
The single most common failure: kids put the Stage 8 script in the wrong sprite. The collision logic goes on the Fish (enemy) sprite, not the Player. Walk the room and confirm before they hit Step 6.
The second most common: the touching dropdown not set to Player. Without it, the wait-until never fires. Have campers click the dropdown and confirm.
The third most common: the broadcast name is playerEaten camelCase, exactly. If it's playereaten (all lowercase) or Player Eaten (with a space), it won't match Stage 4's listener. Have kids read both broadcasts aloud and confirm they match.
For pacing: Step 1–3 (the setup blocks) should take ~30 min. Step 4 (the IF branch) is dense — give it 30 min. Step 5–6 (else + test) should fly. The last 20 min is gameplay testing and tuning, which is fun.
If a camper finishes by minute 70, push them into the medium stretch (tuning). The hard stretch (combo bonus) is great prep for Stage 10 — only push if they're way ahead and have the discipline to keep the codebase clean.
This is the natural mid-course celebration moment. Verbally acknowledge what they just built: "You wrote your first complete game loop."