My First Raspberry Pi Game " Part 06 " A better class of waiting

November 24, 2012 [My First Raspberry Pi Game, Programming Languages, Python, Tech, Videos]

Parts: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12.

Writing your first ever computer program on the Raspberry Pi.

Embedded YouTube video

Today we wait, but better, while we show the ready screen we made last time. In the process we cover two of the most important things you need to understand to write computer programs.

The program we've written so far can wait around for something to happen, but it can't distinguish between the various possible "somethings" that might happen. Specifically, it finishes very abruptly if we even move our mouse over the window!

In this part we'll teach our program to ignore the movements of the mouse, but keep looking out for events it is interested in. We'll also make it able to exit quickly if someone closes its window.

First, we need to get hold of the sys object (actually it's called a "module") which allows us to do things with the system, like quit, which is what we're going to do with it.

Open up LeadPad again, and immediately above the import pygame line, add this:

import sys

Now we're going to write a new function that allows us to exit the game immediately, whenever we want to. Just above the def ready_screen() line, add this new function:

def quit():
    pygame.quit()
    sys.exit()

This function tells PyGame we are finishing (by calling pygame.quit), then exits: sys.exit() stops everything dead.

Finally, we make our waiting a bit posher, by editing the end function look like this:

def end():
    pygame.event.clear()
    event_types_that_cancel = pygame.KEYDOWN, pygame.MOUSEBUTTONDOWN
    waiting = True
    while waiting:
        evt = pygame.event.wait()
        if evt.type == pygame.QUIT:
            quit()
        elif evt.type in event_types_that_cancel:
            waiting = False

There's quite a lot here, but we'll go through it line by line.

First, we clear the events as before using pygame.event.clear to make sure anything that has already happened doesn't interfere with us.

Next we make a variable called event_types_that_cancel that is a list of all the types of events that we care about. They are key presses (KEYDOWN), and mouse clicks (MOUSEBUTTONDOWN). We'll use this variable later.

Now we make another variable, called waiting. We use this to decide when we've finished. We set it to True, which means we are waiting, i.e. we haven't finished.

The next line while waiting is the start of a loop, which means a piece of code we run lots of times. A "while" loop keeps on running until something happens. In this case, the lines after while waiting: will run again and again until the waiting variable becomes False.

The rest of the lines are all "inside" the loop, meaning they run again and again until the loop finishes. Notice that they are indented by a further 4 spaces to show that they are inside. If we had more lines later that were not indented, they would run after the loop had finished.

The first line creates a variable called evt that holds on to what came back when we called the function pygame.event.wait(). This function waits until an event happens. When an event happens, it could be a mouse movement, or a key press, or one of several other types of events. The old version of this code just called pygame.event.wait(), but didn't look at what type of event happened. That's why it finished even when you moved the mouse over the window. This new version captures the event that happened in the evt variable, and then does different things depending on what type of event it was.

The line starting with if lets us decide what to do based on what is happening. The first decision we make is evt.type == pygame.QUIT, which means if the type of event we have found is a special QUIT event. This type of event happens if the user closes the window by clicking the "X" in the top right-hand corner. If this happened, we go on to the next line, which calls the quit() function we created earlier. If this didn't happen, we skip that line, and go on to the next one that is only indented as much as the original if line.

The next line after we skip is the one starting with elif. The "condition" we are checking (decision we are making) is whether evt.type in event_types_that_cancel which means is the event we have seen one of the ones we are interested it - is its type one of the things in event_types_that_cancel. event_types_that_cancel is a list containing the event type for mouse clicks, and the one for key presses, so if something interesting happened we will go to the next line, which is waiting = False. This sets waiting to False, meaning we will stop the loop. If the event was a different type (e.g. a mouse movement), we will skip the waiting = False line as well.

If neither of the conditions was true (so the event was not the user closing the window, or pressing a key or clicking the mouse) then we do nothing in the if and elif bit, and because we're in a loop, we go back to the beginning and wait() again for another event. This goes on forever until one of the events we're interested in happens. When it does, we either quit() immediately, or stop looping because waiting becomes False (meaning the while line lets us escape). When we've stopped looping we carry on, leaving the end function, and get to the end of the program.

If you can understand this you have just grasped two of the most important parts of programming - looping and conditional execution.

I suggest a long cup of tea.

While you're sipping, try out our new program by opening LXTerminal as before, and typing the usual incantation:

./redgreen.py

Notice this time it doesn't quit when you move the mouse, but it does if you click, or press a key, or close the window.

If it doesn't work compare your program with my version: redgreen.py.

Next time we'll make an actual green shape appear, as promised a long time ago!