Introduction to Pygame Zero¶
Creating a window¶
First, create an empty file called intro.py
.
Verify that this runs and creates a blank window by running
pgzrun intro.py
Everything in Pygame Zero is optional; a blank file is a valid Pygame Zero script!
You can quit the game by clicking on the window’s close button or by pressing
Ctrl-Q
(⌘-Q
on Mac). If the game stops responding for any reason, you
may need to terminate it by pressing Ctrl-C
in your Terminal window.
Drawing a background¶
Next, let’s add a draw()
function and set window dimensions. Pygame Zero
will call this function whenever it needs to paint the screen.
In intro.py
, add the following:
1 2 3 4 5 | WIDTH = 300 HEIGHT = 300 def draw(): screen.fill((128, 0, 0)) |
Re-run pgzrun intro.py
and the screen should now be a reddish square!
What is this code doing?
WIDTH
and HEIGHT
control the width and height of your window. The code
sets the window size to be 300 pixels in each dimension.
screen
is a built-in that represents the window display. It has a
range of methods for drawing sprites and shapes. The
screen.fill()
method call is filling the screen with a solid colour,
specified as a (red, green, blue)
colour tuple. (128, 0, 0)
will be a
medium-dark red. Try changing these values with numbers between 0 and 255
and see what colors you can create.
Let’s set up a sprite that we can animate.
Draw a sprite¶
Before we can draw anything, we’ll need to save an alien sprite to use. You can right click on this one and save it (“Save Image As…” or similar).

(This sprite has a transparency (or “alpha”) channel, which is great for games! But it’s designed for a dark background, so you may not be able to see the alien’s space helmet until it is shown in the game).
Tip
You can find lots of free sprites, including this one, on kenney.nl. This one comes from the Platformer Art Deluxe pack.
You need to save the file in the right place so that Pygame Zero can find it.
Create a directory called images
and save the image into it as
alien.png
. Both of those must be lower case. Pygame Zero will complain
otherwise, to alert you to a potential cross-platform compatibility pitfall.
If you’ve done that, your project should look like this:
.
├── images/
│ └── alien.png
└── intro.py
images/
is the standard directory that Pygame Zero will look in to find
your images.
There’s a built-in class called Actor
that you can use to represent a
graphic to be drawn to the screen.
Let’s define one now. Change the intro.py
file to read:
1 2 3 4 5 6 7 8 9 | alien = Actor('alien') alien.pos = 100, 56 WIDTH = 500 HEIGHT = alien.height + 20 def draw(): screen.clear() alien.draw() |
Your alien should now be appearing on screen! By passing the string 'alien'
to the Actor
class, it automatically loads the sprite, and has attributes
like positioning and dimensions. This allows us to set the HEIGHT
of
the window based on the height of the alien.
The alien.draw()
method draws the sprite to the screen at its current
position.
Moving the alien¶
Let’s set the alien off-screen; change the alien.pos
line to read:
alien.topright = 0, 10
Note how you can assign to topright
to move the alien actor by its
top-right corner. If the right-hand edge of the alien is at 0
, the the
alien is just offscreen to the left. Now let’s make it move. Add the following
code to the bottom of the file:
def update():
alien.left += 2
if alien.left > WIDTH:
alien.right = 0
Pygame Zero will call your update()
function once every frame. Moving the
alien a small number of pixels every frame will cause it to slide across the
screen. Once it slides off the right-hand side of the screen, we reset it back
to the left.
Handling clicks¶
Let’s make the game do something when you click on the alien. To do this we
need to define a function called on_mouse_down()
. Add this to the source
code:
1 2 3 4 5 | def on_mouse_down(pos): if alien.collidepoint(pos): print("Eek!") else: print("You missed me!") |
You should run the game and try clicking on and off the alien.
Pygame Zero is smart about how it calls your functions. If you don’t define
your function to take a pos
parameter, Pygame Zero will call it without
a position. There’s also a button
parameter for on_mouse_down
. So we
could have written:
def on_mouse_down():
print("You clicked!")
or:
def on_mouse_down(pos, button):
if button == mouse.LEFT and alien.collidepoint(pos):
print("Eek!")
Sounds and images¶
Now let’s make the alien appear hurt. Save these files:
- alien_hurt.png - save this as
alien_hurt.png
in theimages
directory. - eep.wav - create a directory called
sounds
and save this aseep.wav
in that directory.
Your project should now look like this:
.
├── images/
│ └── alien.png
│ └── alien_hurt.png
├── sounds/
│ └── eep.wav
└── intro.py
sounds/
is the standard directory that Pygame Zero will look in to find
your sound files.
Now let’s change the on_mouse_down
function to use these new resources:
def on_mouse_down(pos):
if alien.collidepoint(pos):
sounds.eep.play()
alien.image = 'alien_hurt'
Now when you click on the alien, you should hear a sound, and the sprite will change to an unhappy alien.
There’s a bug in this game though; the alien doesn’t ever change back to a happy alien (but the sound will play on each click). Let’s fix this next.
Clock¶
If you’re familiar with Python outside of games programming, you might know the
time.sleep()
method that inserts a delay. You might be tempted to write
code like this:
1 2 3 4 5 6 | def on_mouse_down(pos): if alien.collidepoint(pos): sounds.eep.play() alien.image = 'alien_hurt' time.sleep(1) alien.image = 'alien' |
Unfortunately, this is not at all suitable for use in a game. time.sleep()
blocks all activity; we want the game to go on running and animating. In fact
we need to return from on_mouse_down
, and let the game work out when to
reset the alien as part of its normal processing, all the while running your
draw()
and update()
methods.
This is not difficult with Pygame Zero, because it has a built-in
Clock
that can schedule functions to be called later.
First, let’s “refactor” (ie. re-organise the code). We can create functions to set the alien as hurt and also to change it back to normal:
1 2 3 4 5 6 7 8 9 10 11 12 | def on_mouse_down(pos): if alien.collidepoint(pos): set_alien_hurt() def set_alien_hurt(): alien.image = 'alien_hurt' sounds.eep.play() def set_alien_normal(): alien.image = 'alien' |
This is not going to do anything different yet. set_alien_normal()
won’t be
called. But let’s change set_alien_hurt()
to use the clock, so that the
set_alien_normal()
will be called a little while after.
def set_alien_hurt():
alien.image = 'alien_hurt'
sounds.eep.play()
clock.schedule_unique(set_alien_normal, 1.0)
clock.schedule_unique()
will cause set_alien_normal()
to be called
after 1.0
second. schedule_unique()
also prevents the same function
being scheduled more than once, such as if you click very rapidly.
Try it, and you’ll see the alien revert to normal after 1 second. Try clicking rapidly and verify that the alien doesn’t revert until 1 second after the last click.
Summary¶
We’ve seen how to load and draw sprites, play sounds, handle input events, and use the built-in clock.
You might like to expand the game to keep score, or make the alien move more erratically.
There are lots more features built in to make Pygame Zero easy to use. Check out the built in objects to learn how to use the rest of the API.