Learning Goals
3 minBy the end of this lesson you can:
- Describe a level as a list of tuples and build the Actors from it with a loop.
- Explain the difference between
posandtopleft, and say when each is easier. - Write
overlaps(a, b)from the four ways two rectangles can miss each other. - Explain "move first, then repair" and why the repair direction is never a guess.
Warm-Up · Four Ways to Miss
5 minTwo rectangles are lying on a table. Without using the word overlap, list every way they can fail to touch.
There are exactly four:
- A is entirely to the left of B.
- A is entirely to the right of B.
- A is entirely above B.
- A is entirely below B.
Now write the same four sentences using only left, right, top and bottom. For example, "A is entirely to the left of B" becomes a.right <= b.left.
Overlapping is not a fifth idea to learn. It is simply none of those four being true — which is why the function you write in stage 06 is four comparisons joined by and, and why you will never have to look it up again.
New Concept · Level Data and Move-Then-Repair
12 minA level is data, not code. Seven platforms could be seven hand-written Actor(...) lines. Instead, write down where each one starts and how many tiles it is, and let a loop do the typing:
LEVEL = [ (0, 570, 5), # x, y, how many tiles ] platforms = [] for x, y, count in LEVEL: for i in range(count): platforms.append(Actor('platform1', topleft=(x + i * TILE_W, y)))
Tile i simply starts at x + i * 60. Redesigning the whole level later means editing LEVEL and nothing else — which is exactly what you will do for homework.
topleft, not pos. player.pos = (400, 300) puts the centre of the player at that point. topleft=(...) puts the top-left corner there instead. For laying out a grid of tiles, corners are far easier to reason about than centres.
Move first, then repair. This is the idea that makes platformers possible, and it is backwards from what most people try. Do not attempt to stop the player before he moves. Let him move into the platform, notice that he is inside it, and push him back out:
player.y += player.vy # 1. move, possibly into a platform for p in platforms: if overlaps(player, p): # 2. notice player.bottom = p.top # 3. repair: put his feet on the surface
Why is player.bottom = p.top guaranteed to be right? Because of what happened one line earlier. The player only moved downward, so downward is the only direction he can have entered from — so pushing him straight back up is the only sensible repair. There is nothing to guess.
player.vy = 0 after landing stops gravity accumulating while he stands there. Leave it out and he sinks slowly into the tile, gaining speed all the while.
player.on_ground = True records that he has something under his feet. Nothing uses it today. In lesson 4 it is the entire reason you cannot jump in mid-air.
Build Log · Stages 05–06
14 minBuild the platforms
One tile is 60 × 30. A platform is several tiles in a row.
platformer.py · add these pieces
TILE_W = 60 TILE_H = 30 LEVEL = [ (0, 570, 5), # ground, left side (420, 570, 7), # ground, right side - note the gap between them (60, 360, 2), (200, 470, 3), (240, 250, 3), (400, 390, 3), (620, 310, 2), ] platforms = [] for x, y, count in LEVEL: for i in range(count): platforms.append(Actor('platform1', topleft=(x + i * TILE_W, y)))
Then draw them. Platforms go before the player so that he is painted on top:
platformer.py · replace draw()
def draw(): screen.fill((92, 148, 200)) for p in platforms: p.draw() player.draw()
The two ground rows leave a hole between x = 300 and x = 420. That is deliberate: it is the pit, and lesson 5 makes falling into it mean something.
Run it — checkpoint 05
- Seven yellow platforms appear, including a long ground strip with a visible gap in it.
- The player still falls straight through every one of them and off the bottom.
Land on them
First, the overlap test from the warm-up. Add this function above update():
platformer.py · add this function
def overlaps(a, b): """True if two actors' rectangles are touching.""" return (a.right > b.left and a.left < b.right and a.bottom > b.top and a.top < b.bottom)
Then the repair, at the bottom of update() — after the two gravity lines you wrote last lesson:
platformer.py · add at the bottom of update()
player.on_ground = False for p in platforms: if overlaps(player, p): if player.vy > 0: player.bottom = p.top # falling: land on top player.on_ground = True elif player.vy < 0: player.top = p.bottom # rising: bump your head player.vy = 0
Also add player.on_ground = False up with player.vx and player.vy, so the name exists before the first frame runs.
Run it — checkpoint 06
- The player falls and stops on the ground, standing on it.
- Walk him left with A until he reaches the gap: he drops through it. Correct — there is no platform there.
- He cannot reach the floating platforms yet, because he cannot jump.
- If his feet sink into the tile or hover above it, your
subrectnumbers from PLT-01 are wrong.
And now settle last lesson's argument: set MAX_FALL = 100, run, and watch him tunnel straight through the ground he was standing on a moment ago. Put it back to 18.
Try It Yourself
13 minChange the second ground row so the gap is twice as wide, then run and walk into it. Only LEVEL changes — one number.
Hint
The gap runs from the end of the first row to the start of the second. Move the second row's x from 420 to 540 and shorten its tile count from 7 to 5, so it still ends at the right-hand edge.
Add print(len(platforms)) just after the building loop, and work out on paper what it should say before you run it. Then add an eighth platform to LEVEL and check that your arithmetic still matches.
Hint
5 + 7 + 2 + 3 + 3 + 3 + 2 = 25 tiles from seven platforms. If your number is 7, you appended inside the wrong loop.
Mini-Challenge 🔥 · Debug: Nia's Sinking Player
8 minNia's player reaches the ground and then slowly, smoothly sinks into it — a pixel, then two, then four — until he vanishes below the tiles. Here is her landing code. One line is missing and one line is in the wrong place.
player.on_ground = False
for p in platforms:
if overlaps(player, p):
if player.vy > 0:
player.bottom = p.top
player.on_ground = True
player.vy = min(player.vy + GRAVITY, MAX_FALL)
player.y += player.vyTwo questions. Why does he sink faster the longer he stands there? And why does putting the missing line back fix it?
Answer
- Missing:
player.vy = 0after the landing repair. Without it gravity keeps adding0.6every frame, sovyclimbs while he stands still. Each frame he is placed on the surface and then moved further down than the frame before — which is why the sinking accelerates. - Out of place: the gravity and move lines have ended up below the collision loop. The repair must come after the move it is repairing, or it is correcting a position the player has already left.
Order matters as much as content in this file. Every remaining lesson keeps the same rhythm: move, then look, then repair.
Recap
3 minA level is a list of (x, y, count) tuples that a loop turns into tile Actors positioned by topleft. overlaps() is four comparisons: two rectangles touch when none of the four ways to miss applies. Landing is move-then-repair — the player moves into the platform, and because he only moved down, setting player.bottom = p.top is guaranteed to be the right fix. vy = 0 stops the sinking, and on_ground is stored now for the jump next lesson.
Vocabulary Card
- topleft
- An Actor's top-left corner. Easier than
pos(the centre) when laying out a grid. - overlaps(a, b)
- Your own rectangle-overlap test: true when neither box is entirely left, right, above or below the other.
- move-then-repair
- Let the move happen, detect the overlap, then push back out. The direction of the move tells you which way to push.
- on_ground
- A flag you set fresh every frame, recording whether the player has a platform under his feet.
Homework
4 minDesign your own level. Sketch it on squared paper first — one square per tile — then write it as a LEVEL list and run it. Rules: keep the ground gap somewhere, use at least six platforms, and keep every vertical step under 160 pixels (in lesson 4 you learn why that number, not another).
Bring the sketch and a screenshot of the running level.
Hint: the window is 800 × 600, and the ground sits at y = 570. A platform at y = 470 is one hundred pixels above it.
Sample · a staircase level
# A climb from the left, a long drop back down on the right. LEVEL = [ (0, 570, 4), # ground, left of the pit (360, 570, 8), # ground, right of the pit (60, 480, 2), # first step up (180, 400, 2), (300, 320, 2), (420, 240, 3), # the top ledge (660, 400, 2), # a landing on the way down ]
Check your own level against three things: every step is under 160 pixels tall, no platform starts past x = 800, and the pit is wide enough to fall into but narrow enough to jump later. If a platform never gets used, delete it — an unreachable ledge just looks like a bug.