Learning Goals 3 min
By the end of this lesson you will be able to:
- Use say (velocity-y) for (1) seconds as a print-debug — a temporary speech bubble that shows you the live value of a variable while the game runs.
- Switch the on-Stage variable watcher into large mode and use the click-a-block trick to run one suspect block on its own.
- Apply divide-and-conquer — drag half of a long stack to the side of the script area, run, and use whether the bug still appears to halve the search.
Warm-Up — Aisyah's invisible bug 7 min
Aisyah's platformer was working last week. Today she opens it, clicks the flag, and her hero sprite falls through the floor instead of landing on it. She stares at twenty-something blocks and has no idea where the bug is. She sighs and says, "I'll just rewrite the whole thing."
when flag clicked
set [velocity-y v] to (0)
forever
change [velocity-y v] by (-1)
change y by (velocity-y)
if <touching color [#33aa33] ?> then
set [velocity-y v] to (0)
end
end
Without re-reading every block — what's the first thing Aisyah should do to find the bug?
Reveal the answer
Look at the value of velocity-y while the game runs. If she ticks the variable's checkbox in the Variables palette, it shows up on the Stage. The instant she clicks the flag she'll see the number plunge — −1, −2, −3, −10, −50, −200. The bug is now visible: velocity-y never stops growing because the touching-colour check never fires. (Maybe the floor isn't exactly the green she's testing for. Maybe the hero falls past it in one frame because the velocity is bigger than the floor is thick.) The watcher didn't fix the bug — it pointed to where the bug lives. That's what debugging tools do. Today's lesson is five tools like that.
Rewriting from scratch is the most expensive way to fix a bug. By L3 your projects are too big for that. You need tools that let you see inside a running script.
New Concept — five tools for finding bugs 15 min
Every bug is the same shape: the program is doing something, and you don't know what. The fix is always to make the invisible visible. Here are five ways to do that in Scratch — pick the one that matches the bug.
Tool 1 — the print-debug
A print-debug is a temporary block you slip into a stack just to show you a value. In Scratch the easiest one is say (variable) for (1) seconds — drop it into the middle of a loop, with a variable plugged into the round slot, and the sprite will speak the value out loud every loop pass.
when flag clicked
set [velocity-y v] to (0)
forever
change [velocity-y v] by (-1)
say (velocity-y) for (1) seconds
change y by (velocity-y)
end
The number you see in the bubble is the truth — whatever your stack thinks the variable is, that's what shows. If the bubble says −200 and you expected −5, the bug is upstream of the say block. If it says −5 and you expected 0, the bug is downstream. Print-debugs split the script in half.
When you've found the bug, delete the say block. It's a tool, not a feature.
Tool 2 — the on-Stage watcher (large mode)
The print-debug is loud and slow — one bubble per second. For a value that changes fast (like the velocity falling sixty times a second), open the Variables palette, tick the box next to the variable name, and the watcher appears on the Stage. Right-click it and choose large readout — now it's a big number with no label, easy to read from across the room.
The large watcher updates every frame, so you see the number whip past in real time. For fast-changing values, the watcher beats the print-debug.
Tool 3 — click a block to run it alone
Inside the script area, any block you click runs by itself. You don't need a hat. You don't need to click the flag. Click a single move (10) steps and the sprite moves 10 steps, instantly, once. Click a if <touching [edge v]?> then and Scratch runs just that if-check and its body — once.
This is the surgical-tool of debugging. Drag a suspect block out of its stack, click it on its own, watch what happens, then snap it back in. It's the only way to test "does this one block do what I think it does?" without re-running the whole project.
Tool 4 — slow down a forever loop
Forever loops run dozens of times a second. The variable watcher might be a blur. Add a wait (1) seconds temporarily inside the loop and now you can read it frame by frame.
when flag clicked
forever
change y by (velocity-y)
if <touching color [#33aa33] ?> then
set [velocity-y v] to (0)
end
wait (1) seconds
end
This breaks the game (everything moves in slow motion), but breaking the game is the point — you can see each step of the loop in your head while the watcher counts. Once you've found the bug, remove the wait.
Tool 5 — divide and conquer
If you can't tell which half of a 20-block stack holds the bug, cut the stack in half. Grab the bottom half by the topmost block of that half and drag it sideways into empty script-area space. The blocks detach but they don't get deleted — they just sit there.
Click the flag. Does the bug still happen? If yes — the bug is in the half you kept. Drag that half in two. If no — the bug is in the half you set aside. Reattach it, halve it, repeat.
This is the same trick that lets you find a wrong page in a 1000-page book by halving 10 times. Each halving doubles your accuracy. Six halvings on a 64-block project means six clicks to find the bug.
Worked Example — finding Aisyah's gravity bug 12 min
Open a fresh Scratch project, draw a green ground rectangle in the Stage backdrop, drop the cat above it, and type in Aisyah's gravity stack from the warm-up. The hero falls through the floor. We'll find the bug in eight steps using the tools we just met.
Step 1 — Tick the watcher
Variables palette. Tick the box next to velocity-y. The watcher appears in the top-left of the Stage.
Step 2 — Go large
Right-click the watcher → large readout. Now it's a fat number that updates every frame.
Step 3 — Click the flag and watch
Hit the flag. The number plunges: 0, −1, −2, −3, −10, −50, −200. It never stops. The watcher just told you the bug: the touching-colour check that should reset velocity-y to 0 is never firing.
Step 4 — Print-debug the colour check
Slip a say [touching!] for (0.5) seconds inside the if-then to confirm:
when flag clicked
set [velocity-y v] to (0)
forever
change [velocity-y v] by (-1)
change y by (velocity-y)
if <touching color [#33aa33] ?> then
say [touching!] for (0.5) seconds
set [velocity-y v] to (0)
end
end
The cat falls. Never shouts. The if-then never fires. The colour check is wrong.
Step 5 — Click the sensing block on its own
Find touching color [#33aa33]? in the Sensing palette (not in your stack — in the palette). Drag the cat onto the green floor manually with your mouse. Now click the sensing block. Scratch shows a little bubble with the answer — false. So the colour in your block is not the same green as the floor.
Step 6 — Fix the colour
Click the colour swatch on the touching-colour block. Click the eyedropper icon. Click on the floor in the Stage. The swatch becomes the exact pixel colour of the floor. Click your sensing block again — true. Bug found.
Step 7 — Verify the fix
Hit the flag. The cat falls, hits the floor, the watcher freezes at the velocity when contact happened, the cat sits on the floor. Working.
Step 8 — Remove the scaffolding
Delete the say [touching!] block. Optionally untick the watcher (or leave it on while you keep building — your call).
The full assembled stack
when flag clicked
set [velocity-y v] to (0)
forever
change [velocity-y v] by (-1)
change y by (velocity-y)
if <touching color [#33aa33] ?> then
set [velocity-y v] to (0)
end
end
What you just built: not a new feature — a new habit. Every L3 bug from now on starts with the same question: "What value do I expect, and what value am I getting?" The five tools are how you answer it.
Try It Yourself — three debugging drills 15 min
Goal: Build this counter, run it, and use the on-Stage watcher to confirm the count goes up by 1 each second. Don't read past the figcaption until you've watched it for at least ten seconds.
when flag clicked
set [count v] to (0)
forever
change [count v] by (1)
wait (1) seconds
end
Think: You're practising the cheapest debug tool — the watcher. No say blocks, no halving, just one tick in the palette. For any variable you suspect, this is your first move.
Goal: Build this stack. The cat should glide right then say its final x position. But it says the wrong number. Use a print-debug to find out what x position is at three different moments.
when flag clicked
go to x: (-200) y: (0)
glide (2) secs to x: (150) y: (0)
say (x position) for (3) seconds
Think: Slip say (x position) for (1) seconds in before the glide, and during a one-second pause halfway through. The numbers tell you exactly where the cat is at each moment, and whether the final say is reading the right value at the right time.
Goal: Build this thirteen-block stack on a sprite. It is supposed to count to 10 then say "Done!" — but it stops at 5 every time. Use divide and conquer: drag the bottom half away, run the top half alone, see what happens, then halve again.
when flag clicked
set [n v] to (0)
repeat (10)
change [n v] by (1)
if <(n) = (5)> then
stop [this script v]
end
say (n) for (0.3) seconds
end
say [Done!] for (2) seconds
Think: The first halving is between the repeat-end and the final say. If you detach the say and click the flag, the script still stops at 5 — so the bug is in the top half. Halve that next: comment out the if-then by dragging it out. Now it counts to 10. Bug located: the stop [this script v] kills the whole script when n equals 5.
Mini-Challenge — Daniel's frozen platformer 5 min
"My player won't jump after one level"
Daniel's platformer works on level 1 — the player jumps when the spacebar is pressed. After the level-change broadcast, on level 2, pressing space does nothing. He shows you the player's jump script:
when flag clicked
set [can-jump v] to [yes]
forever
if <<key [space v] pressed?> and <(can-jump) = [yes]>> then
set [velocity-y v] to (15)
set [can-jump v] to [no]
wait (1) seconds
set [can-jump v] to [yes]
end
end
Daniel insists "the script doesn't change between levels". Before reading the reveal — which tool from the lesson would you use first, and why?
Reveal one valid solution
Tick the watcher for can-jump. Click the flag, play level 1, jump a few times, watch the value flip yes → no → yes. Now trigger the level-change broadcast. Watch the value during the transition.
The watcher reveals: can-jump is stuck at no after the level change. Somewhere, a script on a different sprite is firing on the level-change broadcast and setting can-jump to no permanently — probably a leftover from a "cutscene" that disables jumping.
Without the watcher, Daniel would stare at the jump script forever and never find the bug — because the bug isn't in the jump script. The watcher made the invisible visible: a variable's value at the wrong moment. That's the whole skill. When a script "doesn't work", the real question is "what does the data look like right now?".
Recap 3 min
You met five debugging tools you'll use for the rest of your Scratch life: the print-debug using say (variable) for (1) seconds; the on-Stage large watcher for fast values; the click-a-block trick to run one block on its own; the slow-down via wait (1) seconds inside a forever; and divide and conquer — halving a long stack by dragging blocks aside. Each tool turns an invisible bug into a visible value. You stop guessing and start measuring.
- Print-debug
- A temporary say (variable) for (1) seconds inserted into a stack to make a sprite speak a value. Removed once the bug is found.
- Watcher (large)
- The on-Stage display of a variable, sized up via right-click → large readout. Updates every frame — better than print-debug for fast-changing values.
- Click-a-block
- Clicking any block in the script area runs just that block, once, without a hat. Use it to test a single suspect block (especially sensing blocks).
- Divide and conquer
- Halve a long stack by dragging the bottom blocks aside. Run. If the bug remains, the top half has it; if not, the bottom half. Repeat to narrow down fast.
- Scaffolding
- Any debug blocks (say, wait, extra watchers) added just to find a bug. Always removed once the fix is in — it's a tool, not a feature.
Homework 2 min
The Bug-Hunt Logbook. Pick any L3 project of yours that you remember having a bug in. Re-find the bug — but this time, record which tool you used.
- Open the project. Reproduce the bug (or just remember what it was).
- Try at least two of the five tools — say, watcher, click-a-block, slow-down, or divide-and-conquer — even if the first one finds the bug.
- Write one short paragraph: "The bug was X. I found it using tool Y because Z."
- Bonus: If your project has no remembered bugs, deliberately break it (delete a random block, change a variable name) and find your own sabotage using the tools.
Save the project as HW-L3-46-Bug-Hunt.sb3. The fixed version, with all debug scaffolding removed.
Bring back next class:
- The
.sb3file. - Your one-paragraph bug-hunt log.
- Your answer to: "Which of the five tools felt the most natural? Which one will you keep forgetting to use?"
Heads up for next class: SCR-L03-47 covers performance — what to do when your big project starts to lag. Too many clones, too many forever loops, too many touching-checks. We'll meet five fixes for projects that have grown too heavy for the browser to keep up.