Управление стрелками Pygame

Управление стрелками в Pygame

Порулим баскетбольным мячом прямо с клавиатуры? Легко! Для этого нужно лишь закодить движение объекта — мяча в зависимости от типа нажатой стрелки на клавиатуре! В качестве основы предлагаю взять код с готовой сценой шириной 500px и высотой 300px, центре которой расположено изображение баскетбольного мяча. Кстати, мячик можно скачать по ссылке: баскетбольный мяч.

Исходные данные: сцена с неподвижным изображением

В исходном варианте сцена с мячом выглядит так:

Управление стрелками в Pygame
Исходная сцена с мячом

Ниже приведен код, который воспроизводит эту сцену в Pygame:

import pygame

# Инициализируем pygame
pygame.init()

# Создаем экран
screen = pygame.display.set_mode((500, 300))

# Загружаем изображение мяча
ball = pygame.image.load('ball.png')

# Задаем начальные координаты
ballX =205
ballY = 110

# Пока игровое поле открыто
while True:
    # Заливаем экран темным цветом
    screen.fill((67, 97, 94))
    # Определяем время задержки
    pygame.time.delay(30)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    # выводим на экран мяч        
    screen.blit(ball, (ballX, ballY))
    # обновляем информацию на экране
    pygame.display.update()

Наша задача: добавить управление стрелками в Pygame

При этом мяч должен передвигаться в сторону, соответствующую направлению нажатой стрелки на клавиатуре. Если нажаты 2 стрелки, например, вверх и вправо, то объект должен двигаться по диагонали в правую верхнюю часть экрана. Мы реализуем 2 варианта перемещения объекта: в первом случае мяч будет двигаться, пока зажата стрелка. Во втором случае длительность нажатия не будет иметь значения. Даже если пользователь будет долго держать кнопку нажатой, мяч все равно не сдвинется дальше значения, указанного в переменной speed. Так как общий принцип работы у обоих вариантов одинаков, и более того — второй вариант является дополненной версией первого, предлагаю приступать к написанию универсального кода прямо сейчас! А изменения в код для превращения первого варианта во второй внесем в заключительном этапе статьи. Итак.., поехали!

1. Объявляем новые переменные

  • Нам понадобится переменная speed для определения расстояния, на которое будет смещаться объект при единичном нажатии стрелок: speed = 20
  • Кроме того, определим переменные возможных направлений движения мяча (to_left, to_right, to_up, to_down). В этих переменных будем хранить булевы значения: True или False. Если, например, значение переменной go_right станет равно True, это послужит сигналом для смещения мяча вправо. Однако, до запуска игрового цикла присвоим всем этим переменным значение False:
go_left = False
go_right = False
go_up = False
go_down = False 

Результат реализации первого пункта — объявлены новые переменные в коде (смотрите подсвеченные строки):

import pygame
pygame.init()

screen = pygame.display.set_mode((500, 300))
ball = pygame.image.load('ball.png')

ballX =205
ballY = 110

# Определяем переменную скорости
# и переменные направления
speed = 20
to_left = False
to_right = False
to_up = False
to_down = False

while True:
    screen.fill((67, 97, 94))
    pygame.time.delay(30)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
      
    screen.blit(ball, (ballX, ballY))
    pygame.display.update()

2. Пишем код для обработки событий

Сначала предлагаю взглянуть на код с добавленными циклами для обработки событий нажатия стрелки и обратного перевода ее в неактивный режим: «if event.type == pygame.KEYDOWN..» и «if event.type == pygame.KEYUP..». Циклы выделены подсветкой и дополнены комментариями. Однако ниже, под кодом, мы подробнее рассмотрим основные моменты:

import pygame
pygame.init()

screen = pygame.display.set_mode((500, 300))
ball = pygame.image.load('ball.png')

ballX =205
ballY = 110

# Определяем переменную скорости
# и переменные направления
speed = 20
to_left = False
to_right = False
to_up = False
to_down = False

while True:
    screen.fill((67, 97, 94))
    pygame.time.delay(30)

    # цикл для обработки событий
    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.key == pygame.K_DOWN:
                to_down = True
            # если была нажата стрелка вверх
            if event.key == pygame.K_UP:
                to_up = 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.key == pygame.K_DOWN:
                to_down = False
            # если этобыла стрелка вверх
            if event.key == pygame.K_UP:
                to_up = False
                
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
      
    screen.blit(ball, (ballX, ballY))
    pygame.display.update()

Пояснения по коду:

Для начала предлагаю рассмотреть существующий цикл отслеживания событий for event in pygame.event.get(). С помощью выражения pygame.event.get() мы получаем список всех событий, которые совершает пользователь при помощи клавиатуры или мыши. После получения списка событий мы последовательно присваиваем каждый объект события переменной event в цикле for. Это же как раз то, что нам нужно! Ведь мы стремимся отследить нажатие стрелок на клавиатуре. И сделать это довольно просто, зная тип объекта event. Мы просто будем сравнивать event.type с pygame.KEYDOWN и с pygame.KEYUP.

1) Сравниваем event.type с pygame.KEYDOWN

Если какая-либо клавиша на клавиатуре нажата, то есть выполняется условие if event.type == pygame.KEYDOWN, то мы можем с помощью атрибута key события event узнать вид нажатой клавиши. Например, если нажата стрелка влево, и выполняется условие event.key == pygame.K_LEFT, то переменной to_left можно присвоить значение True: to_left = True.

Аналогичным образом проверяем клавиши по оставшимся трем направлениям (вверх, вниз и вправо) и, при необходимости, определяем соответствующие переменные to_up, to_down, to_right как True.

2) Сравниваем event.type с pygame.KEYUP

После этого выясним, были ли отпущены какие-либо клавиши. Если выполняется условие event.type==pygame.KEYUP, это значит, что пользователь перестал нажимать какую-либо из клавиш. Осталось лишь с помощью атрибута key события event узнать вид отпущенной клавиши, и если эта клавиша — одна из отслеживаемых нами стрелок, то присвоить соответствующей переменной to_up, to_down, to_right или to_left значение False.

3. Меняем значения координат

На предыдущем шаге мы выяснили, в какую сторону должен смещаться объект. Теперь мы выйдем из цикла обработки событий и зададим смещение координатам ballX и ballY в зависимости от значений переменных направления to_up, to_down, to_left и to_right. Так как в Pygame точка начала координат располагается в левом верхнем углу поля, то для смещения объекта вверх нужно уменьшить ballY на заданную скорость в переменной speed, а для перемещения мяча вправо — увеличить ballX на speed. Добавленные на этом этапе строки выделены подсветкой:

Итоговый код (вариант 1) — управление стрелками в Pygame (объект движется, пока нажата стрелка)

import pygame

# Инициализируем pygame
pygame.init()

# Создаем экран
screen = pygame.display.set_mode((500, 300))

# Загружаем изображение мяча
ball = pygame.image.load('ball.png')

# Задаем начальные координаты
ballX =205
ballY = 110

speed = 20
to_left = False
to_right = False
to_up = False
to_down = False

# Пока игровое поле открыто
while True:
    # Заливаем экран серо-синим цветом
    screen.fill((67, 97, 94))
    # Определяем время задержки
    pygame.time.delay(30)

    # цикл для обработки событий
    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.key == pygame.K_DOWN:
                to_down = True
            # если была нажата стрелка вверх
            if event.key == pygame.K_UP:
                to_up = 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.key == pygame.K_DOWN:
                to_down = False
            # если это была стрелка вверх
            if event.key == pygame.K_UP:
                to_up = False

        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    # В зависимости от значений переменных направления
    # меняем значения координат  
    if to_right:
        ballX += speed
    if to_left:
        ballX -= speed
    if to_down:
        ballY += speed
    if to_up:
        ballY -= speed

    # выводим мяч на экран и обновляем дисплей
    screen.blit(ball, (ballX, ballY))
    pygame.display.update()

Небольшое видео управления мячом — мяч реагирует на долгие и короткие нажатия стрелок:

Заключительный этап, или рассматриваем второй вариант.

После изменения значений координат, наш код можно считать завершенным: объект движется в нужном направлении при нажатии стрелок и совершает остановку при возвращении стрелки в неактивное состояние. Работа программы соответствует первому варианту, о котором было написано в начале статьи. Однако, бывают ситуации в которых необходимо игнорировать длительность нажатия клавиши и совершать короткие шажки при каждом нажатии стрелки. Для этого нужно внести небольшие дополнения в итоговый код — после каждого изменения значения координат ballX или ballY мы будем сбрасывать значение соответствующей переменной направления (to_up, to_down, to_left и to_right) в False. Ниже приведен код для второго варианта передвижения персонажа:

У нас появился Telegram-канал для изучающих Python! Подписывайтесь по ссылке: «Кодим на Python! Вместе «питонить» веселее! 😉

Итоговый код (вариант 2) Управление стрелками в Pygame (один шаг за одно нажатие стрелки)

import pygame

# Инициализируем pygame
pygame.init()

# Создаем экран
screen = pygame.display.set_mode((500, 300))

# Загружаем изображение мяча
ball = pygame.image.load('ball.png')

# Задаем начальные координаты
ballX =205
ballY = 110

speed = 20
to_left = False
to_right = False
to_up = False
to_down = False

# Пока игровое поле открыто
while True:
    # Заливаем экран серо-синим цветом
    screen.fill((67, 97, 94))
    # Определяем время задержки
    pygame.time.delay(30)

    # цикл для обработки событий
    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.key == pygame.K_DOWN:
                to_down = True
            # если была нажата стрелка вверх
            if event.key == pygame.K_UP:
                to_up = 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.key == pygame.K_DOWN:
                to_down = False
            # если это была стрелка вверх
            if event.key == pygame.K_UP:
                to_up = False

        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    # В зависимости от значений переменных направления
    # меняем значения координат  
    if to_right:
        ballX += speed
        to_right = False
    if to_left:
        ballX -= speed
        to_left = False
    if to_down:
        ballY += speed
        to_down = False
    if to_up:
        ballY -= speed
        to_up = False

    # выводим мяч на экран и обновляем дисплей
    screen.blit(ball, (ballX, ballY))
    pygame.display.update()

Небольшое видео управления мячом — мяч двигается в разные стороны короткими шагами:

Добавить комментарий