Learning Goals
3 minBy the end of this lesson you can:
- Move an Actor across the screen by increasing
actor.xinsideupdate(). - Stop the actor at the right edge by checking
actor.xagainstWIDTH. - Wrap the actor back to the left edge so it never disappears.
Warm-Up · Actor Positions
5 minIn PZ-07 you placed an Actor with actor.pos = (x, y) and drew it with actor.draw(). Here is a quick puzzle — what are the x and y values after this code runs?
import pgzrun WIDTH = 600 HEIGHT = 400 cat = Actor("cat") cat.x = 100 cat.y = 200 cat.x = cat.x + 50 pgzrun.go()
Show the answer
cat.x is 150; cat.y is still 200. Adding 50 to cat.x shifts the sprite 50 pixels to the right.
New Concept · update() and actor.x
12 minThink of update() as a heartbeat. Just as your heart beats steadily to keep you moving, update() is called by Pygame Zero once per frame — roughly 60 times a second — to advance the game state. draw() then shows the result on screen.
Moving right
Put your position change inside update(), not inside draw():
def update(): bird.x = bird.x + 3
Every frame, bird.x grows by 3 pixels. After one second that is 180 pixels of travel — fast but smooth.
Stopping at the edge
When bird.x reaches the right side, we clamp it. The right boundary is WIDTH:
def update(): bird.x = bird.x + 3 if bird.x > WIDTH: bird.x = WIDTH
The actor glides right and then freezes at the wall.
Wrapping to the other side
Instead of stopping, we can teleport the sprite back to the left:
def update(): bird.x = bird.x + 3 if bird.x > WIDTH: bird.x = 0
The sprite slides off the right edge and instantly reappears at the left. This creates a looping effect — great for characters that walk forever.
Why it matters
Every moving thing in a game — a character, a bullet, a cloud — uses exactly this pattern: a position variable that changes in update(). Get comfortable with it now and the rest of the module is straightforward.
Worked Example · A Sliding Roti Canai
12 minThe story
Faiz wants a roti canai sprite that slides across the screen and wraps. Save this as sliding_roti.py. We will use a coloured rectangle as a stand-in if you do not have a sprite image — just set roti.image to "alien" or any image you have.
# sliding_roti.py — an actor that moves and wraps import pgzrun WIDTH = 600 HEIGHT = 400 TITLE = "Sliding Roti" roti = Actor("alien") roti.x = 0 roti.y = 200 def draw(): screen.fill("saddlebrown") roti.draw() screen.draw.text("Roti Canai!", topleft=(10, 10), fontsize=24, color="white") def update(): roti.x = roti.x + 3 if roti.x > WIDTH: roti.x = 0 pgzrun.go()
What you will see
Notice that draw() stays simple — it just paints the background and draws the actor at wherever it currently is. The position logic lives entirely in update().
Try It Yourself
13 minEdit sliding_roti.py so the actor moves at 6 pixels per frame instead of 3. Then try 1. Describe the difference in your own words.
Hint
def update(): roti.x = roti.x + 6 # was 3 if roti.x > WIDTH: roti.x = 0
Make the actor slide downward by changing actor.y in update(). Wrap it back to y = 0 when it passes HEIGHT. Start the actor at the top-centre.
Hint
roti.x = 300 roti.y = 0 def update(): roti.y = roti.y + 3 if roti.y > HEIGHT: roti.y = 0
Mini-Challenge · Bounce Off the Walls
8 minAisyah's script is supposed to bounce an actor back and forth across the screen. It moves right but then vanishes — can you spot the bug?
# aisyah_bounce.py — buggy
import pgzrun
WIDTH = 600
HEIGHT = 400
ball = Actor("alien")
ball.x = 300
ball.y = 200
speed = 4
def draw():
screen.fill("black")
ball.draw()
def update():
ball.x = ball.x + speed
if ball.x > WIDTH:
ball.x = WIDTH
speed = -speed
pgzrun.go()It works if…
the actor slides right, hits the edge, then slides back left — forever
Show the fix
# aisyah_bounce.py — fixed import pgzrun WIDTH = 600 HEIGHT = 400 ball = Actor("alien") ball.x = 300 ball.y = 200 speed = 4 def draw(): screen.fill("black") ball.draw() def update(): global speed ball.x = ball.x + speed if ball.x > WIDTH or ball.x < 0: speed = -speed pgzrun.go()
Two fixes: add global speed so the function can reassign the module-level variable, and also check the left edge (ball.x < 0) so the actor bounces both ways.
Recap
3 minTo move an actor, change actor.x (or actor.y) inside update(). Pygame Zero calls update() every frame, so the position shifts smoothly. Check the actor's position against WIDTH or HEIGHT to stop it or wrap it.
Vocabulary Card
- update()
- A function Pygame Zero calls once per frame to advance game logic — move actors, check collisions, update scores.
- actor.x / actor.y
- The Actor's horizontal and vertical position in pixels. Change them to move the sprite.
- WIDTH / HEIGHT
- The window's pixel dimensions. Use them as boundary values in
ifchecks. - Wrapping
- Resetting an actor's position to the opposite edge when it crosses a boundary, so it loops continuously.
Homework
4 minCreate patrol.py. Place an actor at the left edge and make it slide right. When it reaches halfway (WIDTH // 2), stop it there — it should not move any further. Bring a screenshot to the next class.
Stretch. Instead of stopping, make the actor walk back to the left edge and stop there. (Hint: you will need a speed variable and a direction flag.)
Sample · patrol.py
# patrol.py — actor stops at the midpoint import pgzrun WIDTH = 600 HEIGHT = 400 guard = Actor("alien") guard.x = 0 guard.y = 200 def draw(): screen.fill("darkslategray") guard.draw() def update(): if guard.x < WIDTH // 2: guard.x = guard.x + 3 else: guard.x = WIDTH // 2 pgzrun.go()
Your speed value and background colour will differ — the key logic is the if guard.x < WIDTH // 2 check.