Learning Goals
3 minBy the end of this lesson you can:
- State that (0, 0) is the top-left corner and that y increases downward in Pygame Zero.
- Place a filled circle at any (x, y) coordinate on the game window.
- Contrast Pygame Zero's coordinate system with turtle's centre-origin maths system from Level 2.
Warm-Up · Turtle vs Pygame Zero
5 minIn Level 2 you used the turtle module. Turtle puts its origin in the centre of the canvas — going up increases y. In Pygame Zero the origin is the top-left corner and going down increases y.
Predict where this circle ends up in a 400×300 window:
import pgzrun WIDTH = 400 HEIGHT = 300 def draw(): screen.fill("white") screen.draw.filled_circle((0, 0), 20, "red") pgzrun.go()
Show the answer
The circle is centred at (0, 0) — the top-left corner — so you only see the bottom-right quarter of the circle peeking in from the corner.
New Concept · The Screen Grid
12 minThink of the game window as a sheet of graph paper where the top-left corner is stapled to the desk. Moving right increases x. Moving down — toward you — increases y. This is exactly how pixels on a monitor are counted.
Key coordinates in a 600×400 window
Contrast with turtle
The table below shows the key difference between the two systems you now know:
| Feature | turtle (Level 2) | Pygame Zero |
|---|---|---|
| Origin (0, 0) | Centre of canvas | Top-left corner |
| y increases | Upward | Downward |
| Canvas size | Set with setup(w, h) | Set with WIDTH, HEIGHT |
Finding the centre
To centre something, divide width and height by two: (WIDTH // 2, HEIGHT // 2). Using integer division keeps coordinates whole-number pixels.
Worked Example · Dot Placement Grid
12 minThe story
Priya wants to prove she understands the coordinate grid by placing labelled dots at the four corners and the centre. Save as dots.py:
# dots.py — labelled coordinate dots import pgzrun WIDTH = 600 HEIGHT = 400 TITLE = "Coordinate Grid" POINTS = [ ((0, 0), "top-left", "tomato"), ((600, 0), "top-right", "gold"), ((0, 400), "bot-left", "limegreen"), ((600, 400), "bot-right", "deepskyblue"), ((300, 200), "centre", "white"), ] def draw(): screen.fill("black") for pos, label, colour in POINTS: screen.draw.filled_circle(pos, 8, colour) screen.draw.text(label, center=(pos[0], pos[1] + 18), fontsize=18, color=colour) pgzrun.go()
What you'll see
Notice the corner dots near (0, 0) and (600, 0) appear at the very edge of the window — any dot centred at (0, 0) is half off-screen. In a real game, keep sprites at least one radius away from the edge.
Try It Yourself
13 minAdd four more dots at the quarter-points of the window: (150, 100), (450, 100), (150, 300), (450, 300). Give them a new colour and label each one with its coordinate as a string.
Hint
screen.draw.filled_circle((150, 100), 8, "violet") screen.draw.text("(150,100)", center=(150, 118), fontsize=14, color="violet")
Make a dot that starts at (0, 0) and moves right by 2 pixels each frame. When it reaches WIDTH, reset its x back to 0. Use update() to move and draw() to paint.
Hint
dot_x = 0 def update(): global dot_x dot_x = dot_x + 2 if dot_x > WIDTH: dot_x = 0 def draw(): screen.fill("black") screen.draw.filled_circle((dot_x, 200), 10, "orange")
Mini-Challenge 🔥 · Falling Dot
8 minCombine today's coordinates with the update() loop from PZ-02. Make a dot that falls down the screen (y increases each frame). When the dot passes the bottom edge, teleport it back to y = 0 at a random x position. Use random.randint from Level 1.
It works if…
the dot falls from top to bottom, then reappears at a random x at the top
Show one possible solution
# falling_dot.py — uses coordinates + random from L1 import pgzrun import random WIDTH = 480 HEIGHT = 320 dot_x = 240 dot_y = 0 def update(): global dot_x, dot_y dot_y = dot_y + 3 if dot_y > HEIGHT: dot_y = 0 dot_x = random.randint(0, WIDTH) def draw(): screen.fill("midnightblue") screen.draw.filled_circle((dot_x, dot_y), 12, "gold") pgzrun.go()
The key insight: adding to dot_y moves the dot downward because y increases toward the bottom in Pygame Zero.
Recap
3 minIn Pygame Zero (0, 0) is the top-left corner of the window. x increases to the right, and y increases downward. This is different from the turtle coordinate system you used in Level 2, where the origin is centred and y points up. To find the window centre, use (WIDTH // 2, HEIGHT // 2).
Vocabulary Card
- origin
- The (0, 0) point. In Pygame Zero it is the top-left corner of the window.
- x-axis
- Horizontal direction. x increases going right across the screen.
- y-axis
- Vertical direction. y increases going down the screen in Pygame Zero (opposite to maths).
- integer division (//)
- Divides two numbers and discards any remainder, giving a whole-number pixel coordinate.
Homework
4 minDraw a cross-hair on screen: a horizontal line across the full width at HEIGHT // 2 and a vertical line down the full height at WIDTH // 2. Place a filled circle at the centre point where the two lines meet. Save as crosshair.py and bring a screenshot.
Stretch. Display the text "(WIDTH//2, HEIGHT//2)" with the actual numbers (e.g. "(300, 200)") just above the centre circle.
Sample · crosshair.py
# crosshair.py — cross-hair at window centre import pgzrun WIDTH = 600 HEIGHT = 400 TITLE = "Cross-hair" cx = WIDTH // 2 cy = HEIGHT // 2 def draw(): screen.fill("black") screen.draw.line((0, cy), (WIDTH, cy), "limegreen") screen.draw.line((cx, 0), (cx, HEIGHT), "limegreen") screen.draw.filled_circle((cx, cy), 8, "white") screen.draw.text( "(" + str(cx) + ", " + str(cy) + ")", center=(cx, cy - 22), fontsize=20, color="white", ) pgzrun.go()
Your window size can differ. The key technique is using WIDTH // 2 and HEIGHT // 2 so the cross-hair stays centred whatever size you choose.