Pages

Pygame - 2. The Basics




Goal

In this tutorial we will just be getting pygame up and running. Our goal is a small template that produces a blank window that doesn’t hang that we can close with the window X or by pressing escape. Additionally we want to put our frames per second in the title bar, just for good measure.

Import

The first thing we need to do is import the libraries we need, which in this case is pretty much just pygame. Here is a simple try block that you can stick your imports in. If python fails to load a module you need, your script will stop and print a nice informative error message. You’ll see we are importing both pygame and pygame’s locals. Grabbing the locals like this will make your code later on slightly more concise, but isn’t strictly needed to use pygame.

try:
    import pygame
    from pygame.locals import *

except ImportError, err:
    print "%s Failed to Load Module: %s" % (__file__, err)
    import sys
    sys.exit(1)

Game Object and init

Next we are going to create our game object. We don’t necessarily need an object for this, especially because it is so simple, but I’m an object oriented programmer so I think the benefits outweigh the extra lines of code. I like to be able to break down the functionality into different blocks, so our game object is going to have three functions: init for setting everything up, run for running the event loop, and handleEvents which will be called each frame by run. Now some info about pygame. Pygame handles just about everything you might need from rendering to basic collisions to user input to sound. In our basic setup here we are going to need a window to render, the pygame clock for calculating our frames per second, and user input to see if we should quit. We do all this in our init function – line by line we initialize pygame, create a window with a default 800 x 600 resolution, get and store the pygame clock, set a default caption, and tell the pygame event manager that we only want QUIT and KEYDOWN events. We don’t strictly need to do this last part, but since we know exactly what events we want it is easy enough and it will keep our event queue cleaner. You can check all this out in the pygame documentation. The different modules of pygame are across the top and inside they list everything available inside. Sometimes you have to dig a little bit to find what you want, but this is likely going to be your most used resource as you get into really using pygame.

class Game(object):
    """Our game object! This is a fairly simple object that handles the
    initialization of pygame and sets up our game to run."""

    def __init__(self):
        """Called when the the Game object is initialized. Initializes
        pygame and sets up our pygame window and other pygame tools
        that we will need for more complicated tutorials."""

        # load and set up pygame
        pygame.init()

        # create our window
        self.window = pygame.display.set_mode((800, 600))

        # clock for ticking
        self.clock = pygame.time.Clock()

        # set the window title
        pygame.display.set_caption("Pygame Tutorial 2 - Basic")

        # tell pygame to only pay attention to certain events
        # we want to know if the user hits the X on the window, and we
        # want keys so we can close the window with the esc key
        pygame.event.set_allowed([QUIT, KEYDOWN])

Run Method / Event Loop

With the above code our Game object initializes everything, but so far it doesn’t actually DO anything. We’re going to fix that now by adding the main ‘event loop’. Every game has an event loop that drives the game and ours is no exception. Generally this loop defines a single frame of the game – in each iteration the game will do a series of tasks like step the clock, handle user events, process character movement or changes, check for network activity and react accordingly, update the on screen sprites, update the AI, etc, then usually ending with rendering the screen. The time it takes to do all these things is what defines your frames per second – if each iteration of the loop takes 100 milliseconds, your game will run at a maximum of 10 FPS (which is unplayable for anything in real time). In our simple loop we are going to step the pygame clock (which we are using only for calculating the FPS, but in more complicated games we will use the time since the last frame for updating our sprites and such), handle the events in the python event queue, update the title bar with the frames per second, and render the screen. All this is going to be wrapped in a while loop  – when the run() method is called, this will loop as fast as possible until handleEvents() returns false, which we will code next. Something to take note of – we are using pygame.display.flip() to render the screen (flip because we are using double buffering, so each frame switches between buffers and renders the frame). When we have sprites and things we will use a slightly more complicated (but much more efficient) rendering method, so keep an eye out in later tutorials.

def run(self):
    """Runs the game. Contains the game loop that computes and renders
    each frame."""

    print 'Starting Event Loop'

    running = True
    # run until something tells us to stop
    while running:

        # tick pygame clock
        # you can limit the fps by passing the desired frames per seccond to tick()
        self.clock.tick()

        # handle pygame events -- if user closes game, stop running
        running = self.handleEvents()

        # update the title bar with our frames per second
        pygame.display.set_caption('Pygame Tutorial 2 - Basic   %d fps' % self.clock.get_fps())

        # render the screen, even though we don't have anything going on right now
        pygame.display.flip()

    print 'Quitting. Thanks for playing'

HandleEvents Method – Process User Input

The last method we are adding to our Game object is the handleEvents method called in the event loop inside the run function. Pygame uses an event queue for all of its internal stuff (tm), so we need to work with that to get the events we need. For our simple game we only need to know if the user clicks the X (which generates a QUIT event) or if they press their escape key (which generates a KEYDOWN event). You can see all the event functions and the available event types in the pygame docs under the event module. So, we are going to get all the events on the queue with pygame.event.get, then go through them all and test if they are 1. a QUIT event or 2. a KEYDOWN event. If it is a KEYDOWN we will check if the key pressed was escape. Remember, this function is called inside the event loop in run() and the return value determines if the loop will run again or stop. If we find a QUIT event or the escape key is pressed, we return false, which ends the game, otherwise we return true and the loop will just keep running. Note: this simple code could easily just be in the run method, but later on this will contain some complicated code and having it in its own function will help the code be more readable and easier to maintain.

def handleEvents(self):
    """Poll for PyGame events and behave accordingly. Return false to stop
    the event loop and end the game."""

    # poll for pygame events
    for event in pygame.event.get():
        if event.type == QUIT:
            return False

        # handle user input
        elif event.type == KEYDOWN:
            # if the user presses escape, quit the event loop.
            if event.key == K_ESCAPE:
                return False
    return True

Running the Script

The last thing we need is a little section to get our game object and run the game when we call the script. Notice the if name == ‘main‘ line. This will only be true if this is the main script being run (in other words, not being imported by another script). This is very useful when you have a more complicated game structure and you want test code in the modules you are importing.

# create a game and run it
if __name__ == '__main__':
    game = Game()
    game.run()