Reading keyboard¶
Acquiring information about keystrokes on a keyboard is very similar to reading the mouse buttons. Function pg.key.get_pressed()
returns a tuple whose elements are used as logical values, showing for each key on the keyboard whether it is currently being pressed or not.
Because the keyboard has many more keys than the mouse, using indices 0, 1, 2, etc. for certain keys would be impractical. In order not to have to know which index in the tuple corresponds to which key, the PyGame library contains named constants that we use as indices. For example, constants pg.K_LEFT
, pg.K_RIGHT
, pg.K_UP
, pg.K_DOWN
correspond to the frequently used arrow keys. For the space key the corresponding constant is pg.K_SPACE
, while for the letter keys, for example a, b, c the corresponding constants would be pg.K_a
, pg.K_b
, pg .K_c
etc. The complete list of these constants can be seen here .
Examples and tasks¶
Example - Spaceship: In this example, we have an image of a spaceship, which we move left and right in accordance with the pressed arrow keys. In addition, we can fire from the ship by pressing the space bar key.
First, pay attention to the highlighted part of the code with a lighter background (lines 23-37). That part is new here, and it is also commented in more detail in the code itself.
The rest of the program is just animating multiple objects, a technique known from before.

import pygame as pg, petljapg
(width, height) = (400, 400)
canvas = petljapg.open_window(width, height, "Space ship - left, right, fire")
ship = pg.image.load('spaceship.png') # read the image of the space ship
(ship_width, ship_height) = (ship.get_width(), ship.get_height())
(ship_x, ship_y) = (width // 2, height - ship_height // 2) # middle of lower edge
DX = 10 # ship displacement left-right
DY = 10 # bullet displacement up
bullets = []
def new_frame():
global ship_x, ship_y, bullets
# move all the bullets up
new_bullets = []
for x, y in bullets:
if y > DY:
new_bullets.append((x, y - DY))
bullets = new_bullets
# check key presses (left, right, space)
# read the status of all buttons
pressed = pg.key.get_pressed()
# if the left arrow is pressed and the ship can go left
if pressed[pg.K_LEFT] and (ship_x > DX):
ship_x -= DX # move the ship to the left
# if the right arrow is pressed and the ship can go right
if pressed[pg.K_RIGHT] and (ship_x < width - ship_width - DX):
ship_x += DX # move the ship to the rihgt
if pressed[pg.K_SPACE]: # if space is pressed
bullets.append((ship_x, round(0.8 * height))) # add a bullet to the list
# draw
canvas.fill(pg.Color("black"))
canvas.blit(ship, (ship_x - ship_width // 2, ship_y - ship_height // 2))
for bullet in bullets:
pg.draw.circle(canvas, pg.Color('white'), bullet, 3)
petljapg.frame_loop(30, new_frame)
(PyGame__interact_spaceship_arrow_keys_eng)
So, after reading the status of all the keys and placing it in the tuple pressed, we can simply check the status of the keys we are interested in using if statement.
Task - navigation:
Complete the following program so that the 4 arrow keys control the yellow circle, like in the example. The circle should not move if no arrows are pressed and move one pixel in the direction of the arrows that are pressed (opposite arrows cancel each other out).
(PyGame__interact_navigtate1_eng)
Task - snake:
Complete the following program so that the arrows can control a ‘snake’ consisting of several squares, like in the example.
Variables d_row and d_col indicate the direction of movement of the snake. While no arrows are pressed, the value of these variables does not change and the snake continues to move in the same direction. Your task is to add commands for reading the status of the keyboard and calculating new values for (d_row, d_col) based on the arrows pressed, so that the movement continues in the chosen direction.
Hint: if the snake’s head was in the square (row, col), in the new frame it will be in the square (row + d_row, col + d_col). Check if you understood how you should assign values to the variables d_red, d_kol for each direction:
Q-76: If variables (d_row, d_col) are assigned values (0, -1), in which direction does the movement continue?
import pygame as pg, petljapg, random
(width, height) = (400, 400)
canvas = petljapg.open_window(width, height, "Snake")
snake_color = (255, 0, 0) # color of the snake
a = 10 # square size
num_rows, num_cols = height // a, width // a # board size
(d_row, d_col) = (0, 1) # initially one column to the right (per frame)
center = (num_rows // 2, num_cols // 2) # coordinates of the center of the board
snake = [center] * 10 # initially a snake curled up in the center
i_head = 0 # index of the snakes head in the list
done = False
def draw():
canvas.fill(pg.Color("gray")) # paint background
if done:
# Display the game over mesage
font = pg.font.SysFont("Arial", 60)
text_image = font.render("Game over.", True, pg.Color("black"))
x = (width - text_image.get_width()) // 2
y = (height - text_image.get_height()) // 2
canvas.blit(text_image, (x, y))
else:
# draw snake
for row, col in snake:
pg.draw.rect(canvas, snake_color, (col*a, row*a, a, a))
def new_frame():
global snake, i_head, d_row, d_col, done
# HERE CALCULATE THE DISPLACEMENT (d_row, d_col)
# BASED ON THE KEYS PRESSED
# compute the new position of the snake head
row, col = snake[i_head]
i_head = (i_head + 1) % len(snake)
snake[i_head] = (row + d_row, col + d_col)
if col < 0 or col >= num_cols or row < 0 or row >= num_rows:
done = True # snake came out of the board
draw()
petljapg.frame_loop(10, new_frame)
(PyGame__interact_snake_eng)
Questions¶
As you answer the questions, go back to the “snake” program as needed and look up the parts you need to answer.
How many rows does the board have?
Q-77: What are the coordinates of the top left corner of the square (row, col)?
Q-78: Which sentences are true?