Learning Goals
3 minBy the end of this lesson you can:
- Clamp an Actor inside the window using
leftandright. - Detect that the player has fallen out of the world and send him back to the start.
- Write one
respawn()that resets every piece of state a new life needs. - Explain why zeroing
vyinrespawn()is not optional. - Draw text on screen with
screen.draw.text.
Warm-Up · What Does "Back to the Start" Mean?
5 minYour player is falling down the pit at 18 pixels per frame. You are about to teleport him back to his starting position. List everything about him that is not his position, and decide whether each one should be reset too:
player.vx— sideways speed.player.vy— falling speed.player.on_ground— is he standing on something?player.flip_x— which way is he facing?
Put him back at the start while vy is still 18, and on the very next frame he is already falling at full speed — straight back through the pit, before you can press a key. State that survives a respawn is the source of nearly every "I died twice" bug.
New Concept · One Door for Every New Life
12 minBy the end of this module three different things start a fresh life: falling in the pit, running out of health (lesson 7), and pressing R. If each of them resets the player itself, then adding a fourth piece of state means remembering to change three places — and you will miss one.
So all three call the same function:
def respawn(): player.pos = START_POS player.vx = 0 player.vy = 0
It is three lines today. In lesson 6 it also sends the skeletons home; in lesson 7 it refills the health bar. Because there is one door, each of those is a one-line change in one place.
Remember where the start was. Do not re-type the coordinates — capture them:
player.pos = (100, 200) START_POS = player.pos
Now moving the player's starting point is one edit, and respawn() follows automatically.
Falling out of the world. There is no floor under the pit, so the player keeps falling forever. The test is simply whether he has left the window entirely:
if player.top > HEIGHT: respawn()
Use top, not bottom or y, so the respawn fires only once the whole sprite is out of sight. Testing bottom would snatch him back while his head is still visible, which reads as a glitch rather than a fall.
Build Log · Stage 10
14 minStay inside the window
Straight after the sideways collision loop from lesson 4, still inside update():
platformer.py · add after the sideways collision loop
if player.left < 0: player.left = 0 if player.right > WIDTH: player.right = WIDTH
The window edges are being treated exactly like walls — the same repair, without a platform to bump into.
Run it — checkpoint 10a
Hold A or D against an edge: the player stops flush with it and stays fully visible.
The pit means something
Remember the starting position, add the fall test at the very end of update(), and write the function they both need.
platformer.py · add after player.pos
START_POS = player.pos
platformer.py · add the rest
# at the very end of update(): if player.top > HEIGHT: respawn() def respawn(): player.pos = START_POS player.vx = 0 player.vy = 0
Run it — checkpoint 10b
- Walk into the gap. Once you are fully off the bottom of the screen you reappear at the start.
- You reappear standing still, not already plummeting.
- Delete
player.vy = 0for one run to see the difference, then put it back.
A reset key and the controls
Give yourself a manual reset, and tell the player what the keys are.
platformer.py · update these two functions
def on_key_down(key): if key == keys.SPACE and player.on_ground: player.vy = JUMP_SPEED player.on_ground = False elif key == keys.R: respawn() def draw(): screen.fill((92, 148, 200)) for p in platforms: p.draw() player.draw() screen.draw.text("A / D = move SPACE = jump R = respawn", topleft=(10, 10), fontsize=28, color="white")
screen.draw.text takes a position — topleft here, center in lesson 7 — plus a size and a colour. It is drawn after everything else so nothing can cover it. Anything the player must read belongs at the end of draw().
Run it — checkpoint 10
The platformer itself is finished. Check all five:
- You cannot walk off the left or right edge.
- Falling in the pit puts you back at the start, standing still.
- R resets you from anywhere, including mid-jump.
- The controls are written across the top of the screen.
- You can reach every one of the five floating platforms.
Try It Yourself
13 minAdd a falls counter. Start it at 0, add one inside respawn(), and draw it under the controls line. Your first HUD number.
Hint
falls = 0 def respawn(): global falls # respawn() changes a name from outside itself falls += 1 ... # in draw(): screen.draw.text("Falls: %d" % falls, topleft=(10, 40), fontsize=24, color="white")
global is needed because falls is a plain number, not an attribute of an Actor. That is exactly why the player's state lives on player — no global required.
Move the player's start to the top of the highest platform by changing player.pos only. Confirm respawn() follows without any other edit — that is the payoff for capturing START_POS instead of re-typing the numbers.
Then try it the wrong way: hard-code player.pos = (100, 200) inside respawn() as well, change the start again, and watch the two disagree.
Mini-Challenge 🔥 · The Invisible Wall
8 minMia wrote her window-edge clamp like this, and now her player stops about half a body-width short of each edge — as if there were an invisible wall just inside the window.
if player.x < 0:
player.x = 0
if player.x > WIDTH:
player.x = WIDTHTwo questions: what is player.x actually measuring, and what will her player look like when he is pushed against the right-hand edge?
Answer
x is the centre of the Actor, not its edge. Clamping the centre to 0 leaves half the sprite hanging off the left of the window, and clamping it to WIDTH leaves half hanging off the right — so on both sides half the character disappears while the game insists he has stopped.
Using left and right asks about the rectangle's edges, which is what "stay inside the window" actually means. Same idea as topleft versus pos back in lesson 3: pick the anchor that matches the question you are asking.
Recap
3 minWindow edges are walls, clamped with left and right rather than the centre. Falling out of the world is player.top > HEIGHT. Every fresh life goes through one respawn(), which resets position and the velocities — leave vy alone and the new life starts already falling at full speed. START_POS is captured, not re-typed. screen.draw.text at the end of draw() tells the player what the keys do.
Vocabulary Card
- clamp
- Forcing a value to stay inside a range — here, keeping the player's rectangle inside the window.
- respawn
- The single function that returns the game to a playable starting state. Everything that starts a new life calls it.
- HUD
- Heads-up display: text and bars drawn over the game to tell the player what is going on.
- global
- Needed when a function changes a plain module-level name. Not needed for attributes such as
player.hp.
Homework
4 minPlay your own game for five minutes and write a short bug report — three things that feel wrong, ranked. Not crashes: feel. Landing too abruptly? Pit too easy to fall into? Controls text in the way?
For each one, write the single line or number you would change. Do not change it yet — bring the list, because two of them are what lessons 6 and 7 are for.
Hint: get someone who has never seen the game to play it while you watch in silence. Where they hesitate is the bug.
Sample · Leo's bug report
1. Nothing can go wrong except my own footwork. The level is empty, so there is no reason to play it twice. -> not a number. Needs something that moves. (lesson 6) 2. One mistake at the pit costs the whole run. -> a single fall should cost less than everything. (lesson 7) 3. The player lands with a thud but nothing tells me I landed. -> no number either; a sound or a small squash would do. 4. MOVE_SPEED = 5 overshoots the two-tile ledges. -> MOVE_SPEED = 4, or make those ledges three tiles.
A good report separates "change a number" from "write new code". Items 1 and 2 are the next two lessons; item 4 is a one-character fix you can make today. Item 3 is a real observation with no cheap fix — write those down anyway.