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.
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.
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
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.
Pages: 2
Price $15.99
(incl. VAT)