Building a rocks and spaceship game with Pygame Zero

Building a rocks and spaceship
game with Pygame Zero
Establishing the screen area.
Program code:
-----------------------------------------------------#set screen size
WIDTH = 600
HEIGHT = 500
# function to draw things to the screen
def draw():
screen.clear()
-----------------------------------------------------Now save and run this part of the program. You should see a blank window
pop up.
Now add the spacecraft
• There must be a directory (folder) named “images” in your current folder.
In that folder there needs to be an image called ‘spacecraft.png’.
• We need two lines of code to define our spacecraft image, which is called
an “Actor” in pygame zero, and to position the spacecraft on the screen.
Code:
# Create the actors
spacecraft = Actor('spacecraft') # The spacecraft actor
spacecraft.pos = WIDTH/2, HEIGHT/2 # The initial position of the spacecraft
• Place these lines before the draw function. Then you have to draw the
Actor, so put this code in the draw function:
Spacecraft.draw()
About objects and methods
We need some definitions so we know what we’re talking about
•
•
•
•
•
•
‘spacecraft’ is being used as a name to define an “object”.
Think of an object as a model of something real
Objects have ‘data’ and ‘methods’ associated with them.
A method controls the behavior of an object
data is information about the object
‘spacecraft.draw()’ says to apply the draw method to object spacecraft.
That does exactly what you expect. It draws the spacecraft. But where
does it put it?
• spacecraft.pos is used to assign a value to the position data for
‘spacecraft’. So the screen height and width are each divided by two
which gives coordinates for the center of the screen.
• ‘screen’ is an object built in to pygame zero. We had to define spacecraft
to be an object of type “Actor”
• OK, enough of the definitions already!
So now if we save and run the code to this point
we get a spacecraft in the middle of the screen.
Not much of a game yet, is it?
So let’s learn to move the spacecraft.
The update function
• “update()” is executed by pygame zero 60
times per second (as is draw())
• We want to use update() to process keystrokes
• The built in ‘keyboard’ object has data
associated with it. The values ‘right’, ‘left’,
‘up’, and ‘down’ are either True or False
depending on whether the appropriate key is
pressed
• The spacecraft object has x and y coordinates
associated with it that tell draw() where to put it
on the screen.
• The spacecraft object has data describing where
it’s left edge, right edge, top, and bottom are
located on the screen
• So we can test to see if the appropriate edge of
the screen is about to move off screen
• The code to do this is on the next slide. Put the
update function after the draw function.
• The use of ‘and’ means both parts of the if test
must be True for the whole statement to be True
# --------------------------------------# The update function
def update():
# If the cursor keys are pressed, then move the spacecraft.
if keyboard.left:
spacecraft.x -= 2
if keyboard.right:
spacecraft.x += 2
if keyboard.down:
spacecraft.y += 2
if keyboard.up:
spacecraft.y -= 2
# This is fine except we can move offscreen…
# --------------------------------------# The update function
def update():
# If the cursor keys are pressed, then move the
# spacecraft within the limits of the screen.
if keyboard.left and spacecraft.left > 2:
spacecraft.x -= 2
if keyboard.right and spacecraft.right < WIDTH+2:
spacecraft.x += 2
if keyboard.down and spacecraft.bottom < HEIGHT+2:
spacecraft.y += 2
if keyboard.up and spacecraft.top > 2:
spacecraft.y -= 2
A rock!
• Next let’s get a rock to appear and move
across the screen. Later we will vary the
starting position, direction, and speed of the
rock.
• We will do this first in a new program and
then we will pull that part into the spaceship
program.
Code, name this program rock.py:
# Set the size of the window
WIDTH = 600
HEIGHT = 500
# Create the actors
rock = Actor('rock') # Rock actor from rock image
rock.pos = 0, 0
def draw():
screen.clear()
rock.draw()
def update():
rock.x += 1
rock.y += 1
Changing the rock’s path and speed
• Notice that the rock is moving at 45 degrees
left to right across the screen. Why?
• Let’s change it to a shallower angle. How?
• Now let’s make it faster
• Move the starting point for the rock near the
middle (how?) and try a subtraction on rock.x
• So how do make the rock start at some
random point at the top of the screen?
random() function in python
• We want an integer, not a float (number with
a decimal part)
• We use the randint method with the random
function
• We want a random number from 0 to 600, so
random.randint(0, 600) will give us one.
• Code:
rock.pos = random.randint(0, WIDTH), 0
Libraries in python
• It’s not enough to just add the
random.randint() statement, we have to tell
python that we want to use the random
library
• We do that with an “import” statement. This
is usually the first thing in the program.
Code:
import random
Random direction and velocity
• We really want the rock to be different each time it shows up.
So we can get random values to use in our update function.
• Code:
x_change = random.randint(-5,5) # this makes the rock move either
# left to right or right to left
y_change = random.randint(1,5) # keeping to positive numbers
# makes the rock always move down
And make this change:
def update():
rock.x += x_change
rock.y += y_change
Bouncing off the edges
• We can look to see if our next position on the x axis
is going to move off the edge of the screen and if so
change the direction of motion.
Code:
if rock.x + x_change > 600:
x_change = -x_change
elif rock.x + x_change < 0:
x_change = -x_change
• Remember elif?
# about to leave the right edge
# so reverse the x direction
# about to leave the left wall
# so reverse the x direction
Local and global variables
• Variables declared in a function are local to that function.
This means that only in the function where they are declared
can these variables be seen or modified.
• Variable declared at the main program level can be seen
anywhere in the program, but can only be modified from a
function if the are declared as type global
• We can look at some examples
Code:
def update():
global x_change;
global y_change;
Make the rocks keep falling!
• What we’d really like to see in a game is rocks falling one after the
other. Let’s make that change by testing for the rock passing the
bottom of the screen and then restarting it at the top when it does.
Code:
# let's check and see if we're going off the bottom of the screen
if rock.y + x_change > 500:
rock.pos = random.randint(0, WIDTH), 0
x_change = random.randint(-5,5) # this makes the rock move either
# left to right or right to left
y_change = random.randint(1,5) # keeping to positive numbers
# makes the rock always move down
Make the initial positioning code a function.
• The duplicate code can be made into a function and
called from both places it is needed
• x_change and y_change need to be declared as
globals in the function
• Now we don’t have to type it twice!
Collisions
• If we are going to make a projectile to shoot at
a rock then we have to be able to detect when
the rock and the projectile hit each other
• For now, we will put a square on the screen
and try to detect when the rock hits the
square
• A method called “colliderect” will do this for
us
Code, add this line ahead of rock =:
rect_color = (255,0,0)
Code, in def update() add this at end:
if rock.colliderect(box):
#change the rectangle's color
rect_color = (255,255,255)
Code, need to make rect_color a global in update():
global rect_color
A laser beam
• Let’s make a long, skinny rectangle that we
can use as our ‘laser beam’
• When we detect a collision between the rock
and the laser beam, we will blow up the rock
• Code is on next slide
# Set the size of the window
WIDTH = 600
HEIGHT = 500
def draw():
screen.clear()
screen.draw.filled_rect(laser,(255,0,0))
#def update():
# a rectangle is defined by it's bottom left corner
# Rect(bottom left x, bottom left y),(x distance, y distance))
laser = Rect((500, 400), (4, -390))
Make the space bar shoot the laser
• Same type code as checking for arrow keys
• We use the schedule method for the built in clock
object to cause a function to execute after the
desired time has passed
Code:
def update():
global laser
if keyboard.space:
laser = Rect((500, 400), (4, -390)) #put the laser onscreen
clock.schedule(laser_off, 1.0) # turn off after 1 second
def laser_off(): # move the laser back off the screen
global laser
laser = Rect((1500, 1400), (4, -390))
Putting the pieces together
•
•
•
•
Open a new file, lasergame.py
Copy and paste in the spacecraft code
Copy and paste the rock code below that
Now we have to do some cleanup and
eliminate some duplication.
• We are looking for the spaceship being
moveable and a series of rocks falling all in
one game
• Next add the laser code and we will modify
that to actually shoot from the spaceship
• Reminder:
# a rectangle is defined by it's bottom left corner
# Rect(bottom left x, bottom left y),(x distance, y distance))
• We were using this code to test the laser:
laser = Rect((500, 400), (4, -390))
#put the laser onscreen
• We want the laser to fire from the nose of the
spaceship, so we need to find where that nose
is located
laser = Rect((spacecraft.x-2,0),(4,spacecraft.top))
• This goes under “if keyboard.space:” for now
• A problem: the laser fires and stays where it first appears, the
ship can move
• So need to make the laser follow the ship
• To do that we need to redraw the laser every time we redraw
the ship
Code (near top of program):
laser_firing = False
#initialize laser to off
Code (changes in update() function):
if keyboard.space:
laser_firing = True
clock.schedule(laser_off, 1.0) # turn off after 1 second
if laser_firing: # redraw the laser anytime it is firing
laser = Rect((spacecraft.x-2,0),(4,spacecraft.top))
We need noise!
• Let’s add a sound for the laser firing
• Code (add to the keyboard.space section):
sounds.laser.play() # play the laser.wav file
• This will play the file “laser.wav” from the “sounds”
directory
• The file is available on my web site
Collision
• Code (after the globals in update()):
# Check to see if the rock has collided with the spacecraft
collision = spacecraft.colliderect(rock)
# If there has been a collision, then switch both actors to their destroyed versions
if collision and spacecraft.image != ‘spacecraft_destroyed’:
rock.image = 'rock_destroyed'
spacecraft.image = 'spacecraft_destroyed'
gameOver = True
rockLaser = rock.colliderect(laser) # Check to see if the laser has hit the rock
# If the laser has hit the rock and the rock has not already been
# destroyed, then destroy the rock
if rockLaser and rock.image != 'rock_destroyed':
rock.image = 'rock_destroyed'
Reset the images
• Our rock and spaceship are now stuck in destroyed
mode. Let’s do a quick and dirty fix on that
• We can set the rock and spacecraft to their initial
image when we create a new rock
Code (in setup_new_rock()):
rock.image = 'rock'
spacecraft.image = 'spacecraft'
• In the initialization code create BOTH actors before
calling setup_new_rock()
Last but not least: Scores
• Let’s keep track of how many rocks are hit and how
many spacecraft get destroyed
• Create 2 variables as globals in updates() and draw():
global rock_hits
global spacecraft_hits
• Initialize them to 0 at beginning of program
• Increment appropriately in the collision if tests
This game has some problems…
• Rock should just go away and restart when it’s hit;
that’s a pretty easy fix
• A spacecraft should either end the game or maybe
count down the number of spacecraft left, assuming
you get to start with more that one.
• We need a sound for the spacecraft being hit
• You can keep the laser firing constantly. It needs a
“recharge period”
• What else?
We are done with pygame zero!
• At least, we are done with what I think I should show
you for now
• Try making some of the changes listed on the
previous slide on your program.
• I have put some other example programs on my web
page; try modifying some of those if you like.
• For at least a while, you are on your own! Work on
something of your choosing and we will be available
to help you.