Pygame modules for interactive programs

Lead Image © claudia balasoiu, 123RF.com

Special Events

Pygame modules are particularly suited to programming highly interactive software. We look at the modules dedicated to events, sound, and input by keyboard, mouse, and game controller.

In Raspberry Pi Geek issue 03 [1], I introduced you to the graphics functions of the Pygame library [2]. In this article, I'll follow up with the Pygame event, input, and sound modules, which you can use to create games, puzzles, or other interactive programs.

Pygame Events

The main module for dealing with user input is the pygame.event module. Once you start your program, initialize variables, and draw your opening graphics, you probably need to respond to user input to make things happen. That's where the Pygame event loop comes in. Its job is to watch all the different inputs (keyboard, mouse, joysticks, etc.) and process them as they occur. You can also create your own events based on time, game logic, or anything else in your program. More on that a little later.

Listing 1 shows a basic event loop that's about as simple as you can get. The only thing it does is watch for the Pygame window to be closed and exit the program. In line 8, pygame.event.get() returns a list of all pending events. Each returned event has a type that tells me what generated this event. In line 9, I compare the event type to a constant provided by the Pygame module. If it's a pygame.QUIT event, then call sys.exit.

Listing 1

A Basic Event Loop

01 import pygame
02 import sys
03
04 pygame.display.init()
05 screen = pygame.display.set_mode ( ( 320 , 240 ) )
06
07 while 1:
08 for event in pygame.event.get():
09 if event.type == pygame.QUIT:
10     sys.exit()

The type also tells me what other parameters are available for the event. I can pass these extra parameters on to functions I've written to deal with each input. Table 1 shows the Pygame event types and the extra parameters they provide.

Table 1

Pygame Events

Event Type

Parameters

QUIT

None

ACTIVEEVENT

gain, state

KEYDOWN

unicode, key, mod

KEYUP

key, mod

MOUSEMOTION

pos, rel, buttons

MOUSEBUTTONUP

pos, button

MOUSEBUTTONDOWN

pos, button

JOYAXISMOTION

joy, axis, value

JOYBALLMOTION

joy, ball, rel

JOYHATMOTION

joy, hat, value

JOYBUTTONUP

joy, button

JOYBUTTONDOWN

joy, button

VIDEORESIZE

size, w, h

VIDEOEXPOSE

None

USEREVENT

Code

Listing 2 expands the simple event loop example to handle keyboard events. Even though I'm only printing to the console, I still have to initialize a display or window. When that window has focus, keyboard inputs will generate Pygame events. Pygame provides separate KEYDOWN and KEYUP events, so I can respond to both presses and releases of keys. I could use this to turn on a game character's flashlight when I press the space bar, and turn it off when I release it, for example.

Listing 2

Handling Keyboard Events

01 import pygame
02 import sys
03
04 pygame.display.init()
05 screen = pygame.display.set_mode ( ( 320 , 240 ) )
06
07 index = 0
08
09 while 1:
10    for event in pygame.event.get():
11       if event.type == pygame.QUIT:
12          sys.exit()
13       elif event.type == pygame.KEYDOWN:
14          print "{0}: You pressed {1:c}".format ( index , event.key )
15       elif event.type == pygame.KEYUP:
16          print "{0}: You released {1:c}".format ( index , event.key )
17       index += 1

Timed and Programmatic Events

Along with the built-in Pygame events listed in Table 1, I can add my own time-based events or events based on other program logic. Pygame defines pygame.USEREVENT, which is the first event ID that can be assigned to a timer or other condition, and pygame.MAXEVENTS, the highest event ID that can be assigned. Listing 3 shows how to set up a series of timed events.

Listing 3

Timed Events

01 import pygame
02 import sys
03
04 pygame.display.init()
05 screen = pygame.display.set_mode ( ( 320 , 240 ) )
06
07 pygame.time.set_timer ( pygame.USEREVENT , 1000 )
08
09 seconds = 0
10 while 1:
11    for event in pygame.event.get():
12       if event.type == pygame.QUIT:
13          sys.exit()
14       elif event.type == pygame.USEREVENT:
15          seconds += 1
16          print "{0} seconds have elapsed since you started this program".format ( seconds )
17       elif event.type == pygame.KEYDOWN:
18          if event.key == ord ( "s" ): pygame.time.set_timer ( pygame.USEREVENT , 0 )

To set up a timer, call pygame.time.set_timer(), which takes two arguments, the event ID and the amount of time in milliseconds for the event to recur. When the amount of time passes, the event ID provided will appear on the event queue. Line 7 in Listing 3 sets a timer for every 1,000 milliseconds, or once a second.

Line 14 checks whether the event is my timer event (I provided pygame.USEREVENT when I set the timer). If true, 1 second has elapsed, so I increment the seconds counter and print the number of seconds.

Each round of the event loop also checks to see whether the s key has been pressed. In line 18, event.key returns the ASCII value of the character pressed, or a unique scan code for function keys, multimedia keys, and so on, whereas ord (**"s"**) returns the ASCII value of the s key. If the two are equal, then this is the key that has been pressed.

Line 18 also shows how to disable a timer by setting an event timer to 0.

Listing 4 shows an example of a custom user event. Lines 4-7 check the variables passed in to the function; if all are True, lines 6 and 7 generate a Pygame event and place it on the queue.

Listing 4

Custom User Event

01 import pygame
02 import sys
03
04 def checkAllKeys ( a , b , c ):
05    if a == True and b == True and c == True:
06       ev = pygame.event.Event ( pygame.USEREVENT )
07       pygame.event.post ( ev )
08
09 pygame.display.init()
10 screen = pygame.display.set_mode ( ( 320 , 240 ) )
11
12 pressedA = False
13 pressedB = False
14 pressedC = False
15
16 while 1:
17    for event in pygame.event.get():
18       if event.type == pygame.QUIT:
19          sys.exit()
20       elif event.type == pygame.KEYDOWN:
21          if event.key == ord ( "a" ): pressedA = True
22          elif event.key == ord ( "b" ): pressedB = True
23          elif event.key == ord ( "c" ): pressedC = True
24          checkAllKeys ( pressedA , pressedB , pressedC )
25       elif event.type == pygame.USEREVENT:
26          print ( "You have pressed a, b, and c" )

Although it's not used in this example, pygame.event.Event() will also accept a dictionary of additional values as its second argument, which is how I can provide extra parameters, as for all of the built-in Pygame events.

Buy this article as PDF

Express-Checkout as PDF

Pages: 2

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content