First, as always, move into your games directory, create a directory for this week's lab, and move into that. E.g.
cd games mkdir lab7 cd lab7Next, copy across some files for this week's lab: backdrop.gif, ship.gif, star.gif.
Today we'll be creating our python files from scratch, e.g.
gedit lab7a.py &
Once the file has been created, you'll need to make it executable, e.g.
chmod u+x *.py
Pre-amble: clean program structure
#! /usr/bin/python
import sys, pygame, math
# =====================================================================
# GLOBAL VARIABLES
# - list all variables that need to be globally accessible
# define the size of the pygame display window
scrSize = scrWidth, scrHeight = 640,480
gameScreen = None # the main display screen
backImage = None # the loaded background image
scrRefreshRate = 40 # the pause (in milliseconds) between updates
# =====================================================================
# SETUP ROUTINE
# - initializes the pygame display screen and background image
def gameSetup():
global gameScreen, scrSize, backImage
pygame.init()
gameScreen = pygame.display.set_mode(scrSize)
backImage = pygame.image.load('backdrop.gif')
gameScreen.blit(backImage, (0,0))
# =====================================================================
# GAME OBJECTS
# - define the different types of in game objects (e.g. ships,
# characters, etc)
# =====================================================================
# EVENT HANDLING ROUTINE
# - processes any pending in game events,
# returns True if the game should keep playing,
# returns False if the game should quit
def processEvents():
# process each pending event
for event in pygame.event.get():
# if the user closed the window send False back
# to tell the game to quit playing
if event.type == pygame.QUIT:
return False
# if this point is reached then no quit event was
# encountered, so return True to keep playing
return True
# =====================================================================
# MAIN GAME CONTROL ROUTINE
# - sets up the game and runs the main game update loop
# until instructed to quit
def main():
# identify any global variables the main routine needs to access
global gameScreen, backImage, scrRefreshRate
# initialize pygame and the game's display screen
gameSetup()
# run the main game loop
keepPlaying = True
while keepPlaying:
# handle any pending events
keepPlaying = processEvents()
# switch to the new display image
pygame.display.flip()
# pause before initiating the next loop cycle
pygame.time.delay(scrRefreshRate)
# the main game loop has completed, so exit the game
sys.exit()
# =====================================================================
# INITIATE THE GAME
# - calls the main() routine
if __name__ == "__main__":
main()
|
Sprites for in-game objects
Part of our previous lab looked
at reorganizing our game code to use Python classes to hold information
about the various types of objects in our game.
There is also a special PyGame class called Sprites that have a variety of builtin properties and routines that we will look at today.
We will create a GameObject class, based on the PyGame Sprites class, that allows us to do some cleanly automated updating of objects.
Our game object class will have two routines (or methods) associated with it:
# =====================================================================
# GAME OBJECT
# - controls the basic movable in-game objects (ships in this case)
class GameObject(pygame.sprite.Sprite):
# the constructor (initialization routine) for the
# movable game objects
def __init__(self, image, x, y, direction, speed):
# initialize a pygame sprite for the object
pygame.sprite.Sprite.__init__(self)
# load the image for the object
self.origImage = pygame.image.load(image)
self.image = self.origImage
# set up the initial position for the object
self.position = self.x, self.y = x, y
# set up the initial direction for the object
self.facingDir = direction
# set up the initial velocity of the object
self.speed = speed
# the update routine adjusts the object's current position and
# image based on its speed and direction
def update(self):
# update the object's position
self.x = self.x + self.speed[0]
self.y = self.y + self.speed[1]
self.position = self.x, self.y
# update the object's image
self.image = pygame.transform.rotate(self.origImage, self.facingDir)
# center the object's image in its new position
self.rect = self.image.get_rect()
self.rect.center = self.position
|
Updating our in-game objects
The class definition above defines how a "GameObject" works,
but we still need to add code to our main routine to
create the actual game objects we want to see, and to
provide specific initial values for their speed, facing, position,
etc.
We'll revise our main routine to:
# =====================================================================
# MAIN GAME CONTROL ROUTINE
# - sets up the game and runs the main game update loop
# until instructed to quit
def main():
# identify any global variables the main routine needs to access
global gameScreen, backImage, scrRefreshRate
# initialize pygame and the game's display screen
gameSetup()
# create an array of objects to add to the display,
# giving each of them
# an image, xcoord, ycoord, facing, and speed
gameObjList = [
GameObject('ship.gif', 80, 60, 270, [1,1]),
GameObject('ship.gif', 560, 60, 180, [-1,1]),
GameObject('ship.gif', 560, 420, 90, [-1,-1])
]
# create a group for the game objects
objGroup = pygame.sprite.RenderUpdates(*gameObjList)
# run the main game loop
keepPlaying = True
while keepPlaying:
# handle any pending events
keepPlaying = processEvents()
# update the display of the object groups
objGroup.clear(gameScreen, backImage)
# run the updates on each object in the group
objGroup.update()
# switch to the new display image
pygame.display.flip()
# pause before initiating the next loop cycle
pygame.time.delay(scrRefreshRate)
# the main game loop has completed, so exit the game
sys.exit()
|
Updating the display
We're getting closer, but the game display hasn't been told
how/when to redraw the portions of the screen that need to change
based on the movement of our game objects.
This involves two steps:
# =====================================================================
# MAIN GAME CONTROL ROUTINE
# - sets up the game and runs the main game update loop
# until instructed to quit
def main():
# identify any global variables the main routine needs to access
global gameScreen, backImage, scrRefreshRate
# initialize pygame and the game's display screen
gameSetup()
# create the list of screen update sections (rectangles)
updateSections = None
# create an array of objects to add to the display,
# giving each of them
# an image, xcoord, ycoord, facing, and speed
gameObjList = [
GameObject('ship.gif', 80, 60, 270, [1,1]),
GameObject('ship.gif', 560, 60, 180, [-1,1]),
GameObject('ship.gif', 560, 420, 90, [-1,-1])
]
# create a group for the game objects
objGroup = pygame.sprite.RenderUpdates(*gameObjList)
# run the main game loop
keepPlaying = True
while keepPlaying:
# handle any pending events
keepPlaying = processEvents()
# update the display of the object groups
objGroup.clear(gameScreen, backImage)
# run the updates on each object in the group
objGroup.update()
# update the display rectangles
updateSections = objGroup.draw(gameScreen)
# update the buffered display
pygame.display.update(updateSections)
# switch to the new display image
pygame.display.flip()
# pause before initiating the next loop cycle
pygame.time.delay(scrRefreshRate)
# the main game loop has completed, so exit the game
sys.exit()
|
Complete version
Hopefully we can now see three ships moving towards the center
of the screen. (A copy of the complete code is included below.)
#! /usr/bin/python
import sys, pygame, math
# =====================================================================
# GLOBAL VARIABLES
# - list all variables that need to be globally accessible
# define the size of the pygame display window
scrSize = scrWidth, scrHeight = 640,480
gameScreen = None # the main display screen
backImage = None # the loaded background image
scrRefreshRate = 40 # the pause (in milliseconds) between updates
# =====================================================================
# SETUP ROUTINE
# - initializes the pygame display screen and background image
def gameSetup():
global gameScreen, scrSize, backImage
pygame.init()
gameScreen = pygame.display.set_mode(scrSize)
backImage = pygame.image.load('backdrop.gif')
gameScreen.blit(backImage, (0,0))
# =====================================================================
# GAME OBJECT
# - controls the basic movable in-game objects (ships in this case)
class GameObject(pygame.sprite.Sprite):
# the constructor (initialization routine) for the
# movable game objects
def __init__(self, image, x, y, direction, speed):
# initialize a pygame sprite for the object
pygame.sprite.Sprite.__init__(self)
# load the image for the object
self.origImage = pygame.image.load(image)
self.image = self.origImage
# set up the initial position for the object
self.position = self.x, self.y = x, y
# set up the direction for the object
self.facingDir = direction
# set up the initial velocity of the object
self.speed = speed
# the update routine adjusts the object's current position and
# image based on its speed and direction
def update(self):
# update the object's position
self.x = self.x + self.speed[0]
self.y = self.y + self.speed[1]
self.position = self.x, self.y
# update the object's image
self.image = pygame.transform.rotate(self.origImage, self.facingDir)
# center the object's image in its new position
self.rect = self.image.get_rect()
self.rect.center = self.position
# =====================================================================
# EVENT HANDLING ROUTINE
# - processes any pending in game events,
# returns True if the game should keep playing,
# returns False if the game should quit
def processEvents():
# process each pending event
for event in pygame.event.get():
# if the user closed the window send False back
# to tell the game to quit playing
if event.type == pygame.QUIT:
return False
# if this point is reached then no quit event was
# encountered, so return True to keep playing
return True
# =====================================================================
# MAIN GAME CONTROL ROUTINE
# - sets up the game and runs the main game update loop
# until instructed to quit
def main():
# identify any global variables the main routine needs to access
global gameScreen, backImage, scrRefreshRate
# initialize pygame and the game's display screen
gameSetup()
# create the list of screen update sections (rectangles)
updateSections = None
# create an array of objects to add to the display,
# giving each of them
# an image, xcoord, ycoord, facing, and speed
gameObjList = [
GameObject('ship.gif', 80, 60, 270, [1,1]),
GameObject('ship.gif', 560, 60, 180, [-1,1]),
GameObject('ship.gif', 560, 420, 90, [-1,-1])
]
# create a group for the game objects
objGroup = pygame.sprite.RenderUpdates(*gameObjList)
# run the main game loop
keepPlaying = True
while keepPlaying:
# handle any pending events
keepPlaying = processEvents()
# update the display of the object groups
objGroup.clear(gameScreen, backImage)
# run the updates on each object in the group
objGroup.update()
# update the display rectangles
updateSections = objGroup.draw(gameScreen)
# update the buffered display
pygame.display.update(updateSections)
# switch to the new display image
pygame.display.flip()
# pause before initiating the next loop cycle
pygame.time.delay(scrRefreshRate)
# the main game loop has completed, so exit the game
sys.exit()
# =====================================================================
# INITIATE THE GAME
# - calls the main() routine
if __name__ == "__main__":
main()
|