Introduction to Pygame Zero
1. Goals
This tutorial is adapted from the Introduction to Pygame Zero tutorial on Pygame Zero's website. Videos are present in case you need a little extra help completing some of the steps. The objectives for this tutorial are to:
- Practice using the concepts and techniques we have learned so far
- Get familiar using Mu and Pygame Zero
- Make something interesting and fun
2. Starting Mu
Make sure to start Mu in Pygame Zero mode. If not, then any code associated with the Pygame Zero module will not run, and you will get an error message.
Now you can go ahead and save your file. Wherever you save your file now, is where Mu will create your asset folders.
3. Download Assets
We need to download the following images and sound file before we can begin. Download the assets and place them in their proper folders. If you need help watch the video below the files. The images are from Kenny.
4. Hints
As a general rule the import statements should come first, followed by variables and the general game functions, then the draw function, and finally the update function. You also need to make sure that there is only one version of a function.
You can click on the blue down arrows to reveal extra information or hints.
5. Creating a Window
We will start by creating a window with a width of 500 pixels and height of 500 pixels. Enter and play the following code.
WIDTH = 500 HEIGHT = 500
What do you notice? If everything went correctly, you should have noticed a black window pop up with the dimensions of 500px by 500px. The window is black because we have not actually drawn anything to the screen yet. We wil do that next. Update your code with the draw function.
WIDTH = 500 HEIGHT = 500 def draw(): screen.fill((51, 133, 255))
The draw function is called by Pygame Zero whenever it needs to paint the screen. Within the draw function we have a screen.fill()
method call that fills the screen with a solid color. In this case we have filled the screen with
a bluish color. The color is specified with a tuple containing the red, green, and blue values for the color we want. Each value can range from 0 to 255. Try changing the values and see what happens or use a color
picker to choose a value you like. You can also pass a hex value for the color as a string.
Next we will draw a sprite to the screen.
6. Drawing the Sprite
We have done a few things here. We have loaded the sprite by creating an instance of the Actor Class, passed it the filename of our image we want to be our sprite, and saved it as the variable alien. Now we can access various attributes of the
Actor
class using the variable alien
.
In the code below we use the attributes pos
and height
of our sprite.
alien.pos
sets the position of the center our alien sprite to the x and y coordinates given by the tuple (100, 56)
. By using
HEIGHT = alien.height + 20
we set the height of our window to the height of the alien sprite plus 20 pixels.
alien = Actor('alien') alien.pos = (100, 56) WIDTH = 500 HEIGHT = alien.height + 20 def draw(): alien.draw()
Notice that we have changed the draw()
function. We have removed the screen.fill() method and added the alien.draw()
method. This draws our sprite to the screen. Our window should now look like the image below.
Try changing the color of the background by adding back the screen.fill()
method to the
draw
function. What do you notice if you place it after alien.draw()
.
I discuss the code changes and adding a background color in the video below.
7. Moving the Sprite
Before continuing remove the screen.fill()
method from the draw()
function.
Now that we have our sprite on the screen we can make it move. We are going to have our alien move across the screen starting just left of the screen out of view.
Position the alien just left of the screen by changing its topright
atribute. Change the
alien.pos
line to read:
alien.topright = (0, 10)
Run the code to make sure it works. You shouldn't be able to see the alien. Try changing the X value in the tuple for its position and see what you notice. Don't forget to change it back to 0 before you proceed.
Now we are going to create the update()
function. The update()
function is called once every frame. Place the update function at the bottom of the file.
def update(): alien.left = alien.left + 10
When you run the code, hopefully you noticed two things. Click the arrow to the right once you have thought about it.
- The alien is leaving a trail of aliens behind it.
- The alien goes off the right hand side of the screen and does not return.
Let's begin by fixing the first problem. Whenever the update()
function updates the position of the alien by shifting it 10 pixels to the right, Pygame Zero will call the draw()
function. This will draw the alien at the
new shifted location, but we have not removed the old alien. We can get rid of the old alien by using screen.clear()
. Go ahead and place
screen.clear()
in the correct location within the draw()
function and test your code.
Compare your output to the video below and fix your code if your output does not match.
Now we are going to make our alien return back to the left edge once it is off the screen. This will make it look like the alien is looping across the screen.
To do this we will need to add some code to our update()
function. See if you can replace the two question marks in the code below with their correct values.
def update(): alien.left = alien.left + 10 if alien.left > ? : alien.right = ?
Once you think your code is working correctly, click the arrow to check your code.
def update(): alien.left = alien.left + 10 if alien.left > WIDTH: alien.right = 0
The video below explains how our new code works.
8. Interacting with the Alien
Now that we have an alien moving across the screen, it would be nice to be able to interact with it. We are going to add a function to handle mouse clicks.
Add the following code to your program in the appropriate location.
def on_mouse_down(pos): if alien.collidepoint(pos): print("Eek!") else: print("You missed me!")
Now each time we click on the alien, you should see "Eek!" printed to the console below your code. Whenever we miss you should see "You missed me!".
The on_mouse_down()
function is an event handler. Each time the mouse is clicked, the function is called with the mouse pointer position as an argument. The conditional if alien.collidepoint(pos):
checks if the alien
collided with the position of the mouse pointer.
9. Keeping Score
Before moving on make sure your code is well organized and add any comments you think will be helpful later on. This would also be a good time to save your code as another version. You can do this by using Crtl-Shift-s
. This will
let you save a copy of your program with a different name. I encourage you to do this frequently.
I'm going to leave the score keeping exercise up to you. You need to add code to your on_mouse_down()
function so that you can keep score. Your code will need to:
- Initialize a variable
alien.score
to 0 outside of theon_mouse_down()
function - Increase your score and print the updated score to the console when you click on the alien
- Decrease the score and print the updated score to the console when you miss the alien
- Include a background color. You will no longer need
screen.clear()
Show me your progress once you have finished adding your score keeping features so that I can check your code and give you feedback.
10. Progress Check
Before continuing, make sure your game has the following features.
The video below demonstrates each of the features your game should have so far.
11. Adding Sounds
In this section we will add a sound effect that is triggered when you click on the alien. To do this we will use the sounds
object and its play()
method to play the eep.wav
sound file.
We do this by using the pattern sounds.sound_file_name.play()
. In our case since we are using the sound file eep.wav
, our line of code would be sounds.eep.play()
. Click
here for more information on how to use the sounds
object.
Go ahead and add sounds.eep.play()
to the on_mouse_down()
function so that eep.wav
plays when you click on the alien.
12. Animating the Alien
Make sure to save your code as a new version before beginning this section. We will be changing our code around quite a bit and you might need your previous code if all does not go well. Since we will be using an animation to indicate whether
we have clicked on the alien or not, we can delete our print("Eek!")
and print("You missed me!")
lines.
Let's start working on our animation by setting the alien image to alien_hurt.png
when we click on the alien. Place alien.image = "alien_hurt"
in the on_mouse_down()
function so that the image changes when
we click on the alien.
Once you play it, what do you notice? Check your answer by clicking the down arrow.
Hopefully you noticed that once you click the alien, it changes to 'hurt' but does not change back to 'normal'. The video below shows how your game should behave at this point.
This is another good save point. In order to fix our problem with getting the alien back to 'normal' we will need to do some reorganizing (refactoring).
We are going to start by creating a function to handle changing our alien to "normal" and another to change our alien to "hurt". Below is our function to change our alien to "normal".
def change_to_normal(): alien.image = "alien"
The above code is setting the image attribute for alien to alien.png
Next we need to make our function change the alien to "hurt". This is a little trickier. We need this function to change the alien to "hurt" and back to "normal" after a period of time. While we are at it, let's add our sounds.eep.play()
method to the hurt function. This way one function will handle everything related to when we click on the alien. Define the change_to_hurt()
function below the change_to_normal()
function. So far your change_to_hurt()
function
should look like the code below.
def change_to_hurt(): sounds.eep.play() alien.image = "alien_hurt"
Right now the code only plays the "eep" sound and changes our alien to "hurt", but does not change it back to "normal". To do this we will use our change_to_normal()
function along with clock.schedule_unique()
to change
our alien back to "normal" one second after the alien is clicked. This is done by scheduling the change_to_normal()
function to run one second after the change_to_hurt()
function is called. To do this, add the following
line to your change_to_hurt()
function.
clock.schedule_unique(change_to_normal, 1.0)
We have all of the functions we need to make our code work, but we have not actually called them anywhere.
We need to call the change_to_hurt()
function in the on_mouse_down()
function where we check if the alien has been clicked. Since the change_to_hurt()
function takes care of the "eep" sound and changing our
alien to "hurt", replace the sounds.eep.play()
and alien.image = "alien_hurt"
lines in the on_mouse_down()
function with the change_to_hurt()
function
13. Progress Check
Below is a list of the new features we have added. Before continuing make sure your game can now do the following
14. Print to Screen
The score is currently being printed to the console. Next on our list is to display our score on our game screen. We will use the Screen's draw.text()
method. When doing this we need to be aware of a few things.
- Our
screen.draw.text()
needs to go in the draw function - The
draw()
function knows to update the text on the screen whenever thealien.score
changes - We don't need our
print(alien.score)
statements in theon_mouse_down()
function anymore because ofItem 2.
Try to get your score to display on the game screen similar to the example in the video below. The background color does not matter.
15. Customize
If you've made it this far, you should be proud of yourself. Now you get a chance to customize your game. Below are some ideas to help get you started.
- Add background music
- Have the speed change as your score changes
- Change the alien image to something you like
- Add a background image instead of a solid color
- Change the path of the alien during gameplay
- You can lose or win the game
- Game has a start "button"