Python Arena
Step 1 of 3

Events and key presses

So far the main loops have handled one kind of event, pygame.QUIT. But pygame.event.get() hands the program every event: each key pressed or let go, each mouse click, each move of the mouse. Printing them shows what they look like:

import pygame

pygame.init()
window = pygame.display.set_mode((320, 240))

while True:
    for event in pygame.event.get():
        print(event)
        if event.type == pygame.QUIT:
            exit()

    window.fill((0, 0, 0))
    pygame.display.flip()
pygame window320 × 240
The program's window after 20 frames
The window as text
fill (0, 0, 0)
The window after 20 frames (After 5 frames: the A key is pressed. After 8 frames: the A key is let go. After 12 frames: the mouse button is pressed at (100, 60). After 13 frames: the mouse button is let go at (100, 60). After 15 frames: the left arrow is pressed.).
Output
<Event(768-KeyDown {'key': 97, 'mod': 0, 'scancode': 0, 'unicode': 'a'})>
<Event(769-KeyUp {'key': 97, 'mod': 0, 'scancode': 0})>
<Event(1025-MouseButtonDown {'pos': (100, 60), 'button': 1, 'touch': False})>
<Event(1026-MouseButtonUp {'pos': (100, 60), 'button': 1, 'touch': False})>
<Event(768-KeyDown {'key': 1073741904, 'mod': 0, 'scancode': 0, 'unicode': ''})>
<Event(256-Quit {})>

Every event is an object with a type, and each type has attributes of its own. A key event's key is a number for the key: 97 is the A key, and 1073741904 the left arrow. Nobody remembers such numbers, so pygame has a name for each one: pygame.K_a, pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN, pygame.K_SPACE, pygame.K_RETURN and so on. A mouse button event has the point where it happened in pos and the button in button. (On your own computer, the events have a few more details, and there are more of them: one for every move of the mouse over the window, for example.)

The event types have names too:

Type When
pygame.KEYDOWN a key is pressed down
pygame.KEYUP a key is let go
pygame.MOUSEBUTTONDOWN a mouse button is pressed
pygame.MOUSEBUTTONUP a mouse button is let go
pygame.MOUSEMOTION the mouse moves
pygame.QUIT the window is closed

Reacting to keys

To react to a key, check the event's type first and then its key:

import pygame

pygame.init()
window = pygame.display.set_mode((320, 240))

while True:
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                print("left")
            if event.key == pygame.K_RIGHT:
                print("right")
        if event.type == pygame.QUIT:
            exit()

    window.fill((0, 0, 0))
    pygame.display.flip()
pygame window320 × 240
The program's window after 20 frames
The window as text
fill (0, 0, 0)
The window after 20 frames (After 3 frames: the right arrow is pressed. After 4 frames: the right arrow is let go. After 8 frames: the left arrow is pressed. After 9 frames: the left arrow is let go. After 12 frames: the right arrow is pressed. After 13 frames: the right arrow is let go.).
Output
right
left
right

Only a KEYDOWN event has a key that this program cares about, so the KEYUP events pass by without printing anything.

On this site you can try it yourself: run the program, click in its window and press keys. A test gives the events itself, and the task card lists them, such as "After 3 frames: the right arrow is pressed and let go."

Moving with the keys

Now the key presses can move the robot. Each press of an arrow moves it 10 pixels:

The image robot.png
robot.png, 40 × 40 pixels
import pygame

pygame.init()
window = pygame.display.set_mode((320, 240))
robot = pygame.image.load("robot.png")

x = 140
y = 200

while True:
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                x -= 10
            if event.key == pygame.K_RIGHT:
                x += 10
        if event.type == pygame.QUIT:
            exit()

    window.fill((0, 0, 0))
    window.blit(robot, (x, y))
    pygame.display.flip()
pygame window320 × 240
The program's window after 30 frames
The window as text
fill (0, 0, 0)
blit robot.png at (160, 200)
The window after 30 frames (After 5 frames: the right arrow is pressed. After 6 frames: the right arrow is let go. After 10 frames: the right arrow is pressed. After 11 frames: the right arrow is let go. After 15 frames: the right arrow is pressed. After 16 frames: the right arrow is let go. After 20 frames: the left arrow is pressed. After 21 frames: the left arrow is let go.).

Three steps right and one left: the robot ends 20 pixels right of where it started, at (160, 200). The events are handled at the start of each round, before the drawing, so a press shows in the very next frame.

Your task

Challenge 1 of 3

Fill in the blanks so that each press of the up arrow moves the robot 20 pixels up. (The down arrow already moves it down.)

Challenge 2

Write a program that counts jumps. Each press of the space bar prints Jump!, and other keys do nothing. When the window is closed, the program prints how many jumps there were and ends: in the pygame.QUIT branch, print the count and then call exit(). (Do it there, not after the main loop. Here a closed window can't show another frame, so a program that draws again after pygame.QUIT is stopped at its next pygame.display.flip(), and code after its loop never runs.) With three presses of the space bar, it prints:

Jump!
Jump!
Jump!
Jumps: 3

Challenge 3

The robot moves on a grid of 40-pixel tiles. It starts at (140, 100), and each press of an arrow key moves it one tile, 40 pixels, in the arrow's direction: left, right, up or down. It moves when the key goes down, and only once, however long the key is held.