События
До сих пор наши главные циклы выполняли только заранее заданные анимации и реагировали только на события типа pygame.QUIT, хотя цикл получает список всех событий от операционной системы. Теперь разберемся и с другими типами событий.
Обработка событий
Эта программа выводит информацию обо всех событиях, которые операционная система передает программе pygame во время ее работы:
import pygame
pygame.init()
window = pygame.display.set_mode((640, 480))
while True:
for event in pygame.event.get():
print(event)
if event.type == pygame.QUIT:
exit()Предположим, программа некоторое время работала, а затем была нажата кнопка закрытия. Программа выводит следующую информацию:
<Event(4-MouseMotion {'pos': (495, 274), 'rel': (495, 274), 'buttons': (0, 0, 0), 'window': None})>
<Event(4-MouseMotion {'pos': (494, 274), 'rel': (-1, 0), 'buttons': (0, 0, 0), 'window': None})>
<Event(4-MouseMotion {'pos': (492, 274), 'rel': (-2, 0), 'buttons': (0, 0, 0), 'window': None})>
<Event(4-MouseMotion {'pos': (491, 274), 'rel': (-1, 0), 'buttons': (0, 0, 0), 'window': None})>
<Event(5-MouseButtonDown {'pos': (491, 274), 'button': 1, 'window': None})>
<Event(6-MouseButtonUp {'pos': (491, 274), 'button': 1, 'window': None})>
<Event(2-KeyDown {'unicode': 'a', 'key': 97, 'mod': 0, 'scancode': 38, 'window': None})>
<Event(3-KeyUp {'key': 97, 'mod': 0, 'scancode': 38, 'window': None})>
<Event(2-KeyDown {'unicode': 'b', 'key': 98, 'mod': 0, 'scancode': 56, 'window': None})>
<Event(3-KeyUp {'key': 98, 'mod': 0, 'scancode': 56, 'window': None})>
<Event(2-KeyDown {'unicode': 'c', 'key': 99, 'mod': 0, 'scancode': 54, 'window': None})>
<Event(3-KeyUp {'key': 99, 'mod': 0, 'scancode': 54, 'window': None})>
<Event(12-Quit {})>Первые несколько событий связаны с использованием мыши, затем идут события от клавиатуры, и наконец последнее событие закрывает программу. У каждого события есть как минимум тип, но они также могут содержать и другую идентифицирующую информацию, например положение курсора мыши или нажатую клавишу.
Описания событий можно искать в документации pygame, но иногда проще вывести события с помощью кода выше и найти событие, которое возникает, когда происходит то, на что вы хотите реагировать.
События клавиатуры
Эта программа может обрабатывать события, где пользователь нажимает на клавиатуре клавишу со стрелкой вправо или влево. Программа выводит, какая клавиша была нажата.
import pygame
pygame.init()
window = pygame.display.set_mode((640, 480))
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()Константы pygame.K_LEFT и pygame.K_RIGHT относятся к клавишам со стрелками влево и вправо. Константы клавиш pygame для разных клавиш на клавиатуре перечислены в документации pygame.
Например, если пользователь дважды нажмет стрелку вправо, затем один раз стрелку влево, а затем еще раз стрелку вправо, программа выведет:
right
right
left
rightТеперь у нас есть все инструменты, необходимые для перемещения персонажа, или спрайта, по экрану вправо и влево с помощью клавиш со стрелками. Следующий код делает именно это:
import pygame
pygame.init()
window = pygame.display.set_mode((640, 480))
robot = pygame.image.load("robot.png")
x = 0
y = 480-robot.get_height()
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()В зависимости от того, как вы используете клавиши со стрелками, запуск программы может выглядеть так:

В коде выше у нас есть переменные x и y, которые содержат координаты положения спрайта. Переменная y задана так, чтобы спрайт появлялся внизу окна. Значение y не меняется в течение выполнения программы. А значение x увеличивается на 10 каждый раз, когда пользователь нажимает стрелку вправо, и уменьшается на 10 каждый раз, когда нажимается стрелка влево.
Программа в целом работает довольно хорошо, но клавишу нужно нажимать снова каждый раз, когда мы хотим снова сдвинуться. Было бы лучше, если бы движение продолжалось, пока клавиша удерживается. Следующая программа предлагает такую функциональность:
import pygame
pygame.init()
window = pygame.display.set_mode((640, 480))
robot = pygame.image.load("robot.png")
x = 0
y = 480-robot.get_height()
to_right = False
to_left = False
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
to_left = True
if event.key == pygame.K_RIGHT:
to_right = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
to_left = False
if event.key == pygame.K_RIGHT:
to_right = False
if event.type == pygame.QUIT:
exit()
if to_right:
x += 2
if to_left:
x -= 2
window.fill((0, 0, 0))
window.blit(robot, (x, y))
pygame.display.flip()
clock.tick(60)Код теперь содержит переменные to_right и to_left. Они хранят информацию о том, должен ли спрайт двигаться вправо или влево в данный момент. Когда пользователь нажимает клавишу со стрелкой, значение в соответствующей переменной становится True. Когда клавиша отпускается, значение меняется на False.
Часы используются для синхронизации движений спрайта, так что они потенциально происходят 60 раз в секунду. Если нажата клавиша со стрелкой, спрайт сдвигается на два пикселя вправо или влево. Это означает, что спрайт движется со скоростью 120 пикселей в секунду, если клавиша удерживается нажатой.
События мыши
Следующий код реагирует на события, где кнопка мыши нажата, пока курсор находится в области окна:
import pygame
pygame.init()
window = pygame.display.set_mode((640, 480))
while True:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
print("you pressed the button number", event.button, "at location", event.pos)
if event.type == pygame.QUIT:
exit()Выполнение этой программы должно выглядеть примерно так:
you pressed the button number 1 at location (82, 135)
you pressed the button number 1 at location (369, 135)
you pressed the button number 1 at location (269, 297)
you pressed the button number 3 at location (515, 324)Кнопка номер 1 означает левую кнопку мыши, а кнопка номер 3 означает правую кнопку мыши.
Следующая программа объединяет обработку событий мыши и рисование изображения на экране. Когда пользователь нажимает кнопку мыши, пока курсор мыши находится в границах окна, в этом месте рисуется изображение робота.
import pygame
pygame.init()
window = pygame.display.set_mode((640, 480))
robot = pygame.image.load("robot.png")
while True:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
x = event.pos[0]-robot.get_width()/2
y = event.pos[1]-robot.get_height()/2
window.fill((0, 0, 0))
window.blit(robot, (x, y))
pygame.display.flip()
if event.type == pygame.QUIT:
exit()Выполнение программы может выглядеть так:

Следующая программа содержит анимацию, где спрайт робота следует за курсором мыши. Положение спрайта хранится в переменных robot_x и robot_y. Когда мышь движется, ее положение сохраняется в переменных target_x и target_y. Если робот не находится в этом месте, он движется в нужном направлении.
import pygame
pygame.init()
window = pygame.display.set_mode((640, 480))
robot = pygame.image.load("robot.png")
robot_x = 0
robot_y = 0
target_x = 0
target_y = 0
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
target_x = event.pos[0]-robot.get_width()/2
target_y = event.pos[1]-robot.get_height()/2
if event.type == pygame.QUIT:
exit(0)
if robot_x > target_x:
robot_x -= 1
if robot_x < target_x:
robot_x += 1
if robot_y > target_y:
robot_y -= 1
if robot_y < target_y:
robot_y += 1
window.fill((0, 0, 0))
window.blit(robot, (robot_x, robot_y))
pygame.display.flip()
clock.tick(60)Выполнение программы должно выглядеть примерно так:

Текущие баллы можно посмотреть в синем индикаторе в правом нижнем углу страницы.