Part I: Python and PyGame continued ...

In this section we'll continue with the "bouncing star" example we started in the last lab, incorporating the material discussed in lectures yesterday, and then move on to cover event handling.

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 lab3
   cd lab3
Next, copy across some files for this week's lab (right click and 'save as' to the appropriate folder) bck_ocean.gif, star.gif, and game2.py)

The game2.py file is a (slightly cleaned up) version of last week's lab, with the addition of a background image instead of the flat black screen.

Run the chmod command to make the program executable, then try running the game to make sure it works, i.e.:


chmod  u+x  game2.py
./game2.py

Take a moment to review the code before progressing with the rest of the lab:
#! /usr/bin/python

# import and initialize the pygame module
import pygame
pygame.init()

# print an initialization message on the control console
print "Starting game console"

# set our desired screen width and height (in pixels)
screenSize = screenWidth,screenHeight = 400,320

# open a display window of the specified size
display = pygame.display.set_mode(screenSize)

# load images for the display background and the moving star
background = pygame.image.load("bck_ocean.gif")
starImage = pygame.image.load("star.gif")

# set up a box to track the position of the star
starBox = starImage.get_rect()

# establish an initial speed for the star [horizontal, vertical]
starSpeed = [4,4]  # each turn moves 4 pixels right, 4 pixels down

# the keepPlaying variable allows us to continue playing
#     as long as it is set to True
keepPlaying = True

while keepPlaying:

   # start of the keepPlaying while loop

   # adjust the position of the star's containing "box"
   #    based on its current speed
   starBox = starBox.move(starSpeed)

   # if the star goes off the left or right edge
   #    reverse its horizontal speed
   if starBox.left < 0 or starBox.right > screenWidth:
      starSpeed[0] = - starSpeed[0] 
      print "Bounced: new speed", starSpeed

   # Note that [0] refers to the first thing in the speed list
   #    while [1] refers to the first thing in the speed list

   # if the star goes off the top or bottom edge
   #    reverse its vertical speed
   if starBox.top < 0 or starBox.bottom > screenHeight:
      starSpeed[1] = - starSpeed[1]
      print "Bounced: new speed", starSpeed

   # redraw the background picture to the screen buffer
   display.blit(background, (0,0))
   # redraw the star (in its new position) to the screen buffer
   display.blit(starImage, starBox)

   # update the visible display from the screen buffer
   pygame.display.flip()

   # pause for 40 milliseconds before continuing
   pygame.time.delay(40)

   # check for any events that have taken place during
   #    this turn (keypresses, mouseclicks, etc)
   for event in pygame.event.get():

      # start of the events for loop

      # check to see if the player clicked the window close box
      if event.type == pygame.QUIT:
         keepPlaying = False
	 print "Player command: close window"

      # end of the events for loop

   # end of the keepPlaying while loop

# print a termination message on the control console
print "shutting down the game"

Positioning the star using the enclosing rectangle (starBox)

In our original version, we simply allowed the star to begin in the default location (0,0 - the upper left corner of the window).

This time, we'll use its starBox container to place it in the center of the window.

starBox (and any bounding box created using the get_rect() routine) has a variety of properties that tell us where it is currently located and allow us to set a new location:

#  starBox.x       the star's horizontal position in the window
#  starBox.y       the star's vertical position in the window
#  starBox.left    the position of the star's left edge
#  starBox.right   the position of the star's right edge
#  starBox.top     the position of the star's top edge
#  starBox.bottom  the position of the star's lower edge
If we want the star to begin in the middle of the window, we can calculate where the middle is (from the width and height of the window) then set the starBox x and y coordinates:
   starBox.x = screenWidth / 2
   starBox.y = screenHeight / 2
Try adding that code to game2.py just after the starBox is created. I.e. just under the line
starBox = starImage.get_rect()

Try running ./game2.py to see if it has been correctly positioned.

Next, try altering the initial screenSize and see if it still places the star in the center of the screen correctly.


Allowing the user to quit by hitting the q or <escape> keys

Near the bottom of game2.py, at the end of the while loop, you'll find the code that processes any events that have taken place since the last pass through the while loop. (Events include keypresses, mouseclicks, etc.)

The event processing is handled with a for loop, which basically says

     for each event that is ready
         ... do this to check/process it ...
The actual code for the loop currently looks like:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         keepPlaying = False
	 print "Player command: close window"
This simply checks to see if the user has clicked the close X in the upper right corner of the window, setting variable keepPlaying to False if they have.

Then, the next time we get to the start of the while keepPlaying: loop it will realize it's time to stop playing and will bypass the loop.

What we will add now are two more ways for the player to quit: either by hitting the escape key or by pressing the letter q on the keyboard.

Each time a player presses a key on the keyboard it generates a KEYDOWN event, and stores which specific key they pressed as extra information.

We will simply look for any KEYDOWN events, and see if the pressed key was the q or the escape key, e.g.

      # check to see if the player pressed any keys
      if event.type == pygame.KEYDOWN:
	 # treat the Q and escape keys as quit commands
	 if event.key == pygame.K_q:
            keepPlaying = False
	    print "Player command: quit (q)"
	 elif event.key == pygame.K_ESCAPE:
            keepPlaying = False
	    print "Player command: quit (escape)"
Add that code to the bottom of the for loop, save the file, and try running the game.

See if it allows you to quit simply by pressing escape.

If that works, see if it allows you to quit simply by pressing the letter q.


Let the user change the speed of the star with the arrow keys

Next, we'll add events that change the speed of the star whenever the player presses one of the arrow keys.

If the player presses the right arrow we'll add 1 to the horizontal speed, whereas if they press the left arrow we'll subtract 1.

Similarly, if the player presses the down arrow we'll add 1 to the vertical speed, whereas if they press the up arrow we'll subtract 1.

Remember that speeds are stored as a list (e.g. [4,3]) where the first element is the horizontal speed and the second is the vertical.

As an example, to increment the horizontal speed we can use
starSpeed[0] = starSpeed[0] + 1
(The [0] refers to the thing in the first position in the list.)

Now we need to detect when the player has pressed an arrow, i.e. more things to check in our KEYDOWN section.

First, let's just try the right arrow key, adding this just before or just after our tests for 'q' and :

         # if the player pressed a right arrow then 
	 #    adjust the horizontal speed
         if event.key == pygame.K_RIGHT:
	    starSpeed[0] = starSpeed[0] + 1
	    print "Player command: increase rightward speed", starSpeed
Save and try running the game, hitting the right arrow key a bunch of times to see if it is picking up speed.

Once that works, try adding the code for the rest of the arrow keys:

         # if the player pressed an arrow key then adjust
	 #    the horizontal or vertical speed
         if event.key == pygame.K_RIGHT:
	    starSpeed[0] = starSpeed[0] + 1
	    print "Player command: increase rightward speed", starSpeed
	 elif event.key == pygame.K_LEFT:
	    starSpeed[0] = starSpeed[0] - 1
	    print "Player command: decrease rightward speed", starSpeed
	 elif event.key == pygame.K_UP:
	    starSpeed[1] = starSpeed[1] - 1
	    print "Player command: decrease falling speed", starSpeed
	 elif event.key == pygame.K_DOWN:
	    starSpeed[1] = starSpeed[1] + 1
	    print "Player command: increase falling speed", starSpeed
Again, save and run the game and see if you can control the speed of the star successfully.

Wrap up

The final completed lab should look something like this, with the key new work highlighted:

#! /usr/bin/python

# import and initialize the pygame module
import pygame
pygame.init()

# print an initialization message on the control console
print "Starting game console"

# set our desired screen width and height (in pixels)
screenSize = screenWidth,screenHeight = 400,320

# open a display window of the specified size
display = pygame.display.set_mode(screenSize)

# load images for the display background and the moving star
background = pygame.image.load("bck_ocean.gif")
starImage = pygame.image.load("star.gif")

# set up a box to track the position of the star
starBox = starImage.get_rect()

# start the star out in the center of the screen
#    by setting its x,y coordinates 
starBox.x = screenWidth / 2
starBox.y = screenHeight / 2

# establish an initial speed for the star [horizontal, vertical]
starSpeed = [4,4]  # each turn moves 4 pixels right, 4 pixels down

# the keepPlaying variable allows us to continue playing
#     as long as it is set to True
keepPlaying = True

while keepPlaying:

   # start of the keepPlaying while loop

   # adjust the position of the star's containing "box"
   #    based on its current speed
   starBox = starBox.move(starSpeed)

   # if the star goes off the left or right edge
   #    reverse its horizontal speed
   if starBox.left < 0 or starBox.right > screenWidth:
      starSpeed[0] = - starSpeed[0] 
      print "Bounced: new speed", starSpeed

   # Note that [0] refers to the first thing in the speed list
   #    while [1] refers to the first thing in the speed list

   # if the star goes off the top or bottom edge
   #    reverse its vertical speed
   if starBox.top < 0 or starBox.bottom > screenHeight:
      starSpeed[1] = - starSpeed[1]
      print "Bounced: new speed", starSpeed

   # redraw the background picture to the screen buffer
   display.blit(background, (0,0))
   # redraw the star (in its new position) to the screen buffer
   display.blit(starImage, starBox)

   # update the visible display from the screen buffer
   pygame.display.flip()

   # pause for 50 milliseconds before continuing
   pygame.time.delay(50)

   # check for any events that have taken place during
   #    this turn (keypresses, mouseclicks, etc)
   for event in pygame.event.get():

      # start of the events for loop

      # check to see if the player clicked the window close box
      if event.type == pygame.QUIT:
         keepPlaying = False
	 print "Player command: close window"

      # check to see if the player pressed any keys
      if event.type == pygame.KEYDOWN:

         # if the player pressed an arrow key then adjust
	 #    the horizontal or vertical speed
         if event.key == pygame.K_RIGHT:
	    starSpeed[0] = starSpeed[0] + 1
	    print "Player command: increase rightward speed", starSpeed
	 elif event.key == pygame.K_LEFT:
	    starSpeed[0] = starSpeed[0] - 1
	    print "Player command: decrease rightward speed", starSpeed
	 elif event.key == pygame.K_UP:
	    starSpeed[1] = starSpeed[1] - 1
	    print "Player command: decrease falling speed", starSpeed
	 elif event.key == pygame.K_DOWN:
	    starSpeed[1] = starSpeed[1] + 1
	    print "Player command: increase falling speed", starSpeed

	 # treat the Q and escape keys as quit commands
	 elif event.key == pygame.K_q:
            keepPlaying = False
	    print "Player command: quit (q)"
	 elif event.key == pygame.K_ESCAPE:
            keepPlaying = False
	    print "Player command: quit (escape)"

      # end of the events for loop
   # end of the keepPlaying while loop
# print a termination message on the control console
print "shutting down the game"


Part II: image and sound creation and resources

The remainder of the lab is an opportunity to examine some of the tools and resources available for the images and sound effects you may wish to create or use in your games.

The sections below provide a short collection of resources on finding or creating images, sound effects, and music for your games.

GIMP and image editing

GIMP is freely available from gimp.org, and a wide variety of tutorials are available. Many decent gimp tutorials are linked here.

In particular, you might begin with the guide from minihowto.org . (This is clearer than most, and provides decent screenshots.)

From there, you might check out the guides on YouTube, or start working through some of the core tutorials at gimp.org:

Image resources

As we discussed in class, creation of the images needed for a game is incredibly time consuming. For small, do-it-yourself projects it is often more effect to find community resources (and check to make sure you have the rights to use those resources of course).

Many sites host resource collections, a few examples are linked below.

Sound resources

As with the image resources, creating all the sound effects needed for a game is another time consuming process. Again, there are community resources available for use (again, with the proviso that you check first to ensure you have the rights to use them):

While we will not explicitly go over it in 171, there is a freely available sound editor: Audacity, with a number of decent tutorials: