Любая, даже самая простая игра предполагает взаимодействие с пользователем. Часто для этого используется клавиатура (или тачпад) или мышь. На этом занятии мы с вами увидим как происходит обработка событий от клавиатуры и какие нюансы здесь существуют.
Вообще, за обработку событий отвечает модуль
и ранее мы уже познакомились с методом
- event.type == pygame.KEYDOWN – клавиша нажата;
- event.type == pygame.KEYUP – клавиша отпущена.
import pygame pygame.init() W = 600 H = 400 sc = pygame.display.set_mode((W, H)) pygame.
display.set_caption(«События от клавиатуры») pygame.display.set_icon(pygame.image.
load(«app.bmp»)) WHITE = (255, 255, 255) BLUE = (0, 0, 255) GREEN = (0, 255, 0) RED = (255, 0, 0) FPS = 60 # число кадров в секунду clock = pygame.time.
Clock() x = W // 2 y = H // 2 speed = 5 while 1: for event in pygame.event.
get(): if event.type == pygame.QUIT: exit() elif event.type == pygame.KEYDOWN: if event.
Лучший способ изучить Python это PyGame | Игры
key == pygame.K_LEFT: x -= speed elif event.key == pygame.K_RIGHT: x += speed sc.fill(WHITE) pygame.draw.
rect(sc, BLUE, (x, y, 10, 20)) pygame.display.update() clock.
tick(FPS)
Смотрите, нажимая на курсорные клавиши, происходит изменение координаты x и прямоугольник перерисовывается в новой позиции. Но, если нажать и удерживать клавишу нажатой, то объект сместится только один раз. Постоянного перемещения не происходит, как можно было ожидать.
Все дело в том, что при нажатии клавиши в PyGame формируется только одно событие pygame.KEYDOWN. После того, как мы его прочитали из очереди и обработали, повторного такого события там уже нет и, соответственно, условие event.type == pygame.KEYDOWN не срабатывает. Если мы все же хотим, чтобы при удержании клавиши, прямоугольник постоянно перемещался, то, конечно, это можно реализовать так:
flLeft = flRight = False while 1: for event in pygame.event.get(): if event.type == pygame.
QUIT: exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: flLeft = True elif event.
key == pygame.K_RIGHT: flRight = True elif event.type == pygame.KEYUP: if event.key in [pygame.
K_LEFT, pygame.K_RIGHT]: flLeft = flRight = False if flLeft: x -= speed elif flRight: x += speed sc.fill(WHITE) pygame.draw.
rect(sc, BLUE, (x, y, 10, 20)) pygame.display.update()
Здесь мы по событию pygame.KEYDOWN изменяем состояния флагов flLeft или flRight в зависимости от нажатия на левую или правую курсорные клавиши. А в основном цикле по этим флагам осуществляем изменение координат прямоугольника. Теперь, он перемещается непрерывно, удерживая клавишу нажатой.
При отпускании клавиши генерируется событие pygame.KEYUP и флаги flLeft, flRight устанавливаются в False, движение прекращается. У вас может возникнуть вопрос: а зачем нам вторая проверка if event.key in [pygame.K_LEFT, pygame.K_RIGHT] Это защита от двойных нажатий. Например, удерживая нажатой курсорную клавишу, мы нажимаем, а потом отпускаем еще какую-нибудь.
Как обрабатывать события от клавиатуры | Pygame #3
Тогда без этой второй проверки по событию pygame.KEYUP флаги flLeft, flRight станут равными False и движение остановится. Хотя, курсорная клавиша остается нажатой. Чтобы этого не происходило и делается эта дополнительная проверка. Однако, тот же самый функционал можно реализовать проще, используя модуль работы с клавиатурой pygame.key В частности, в нем есть функция: pygame.key.get_pressed() которая возвращает информацию о состояниях клавиш в виде кортежа: Если клавиша с определенным индексом нажата, то в этом кортеже ее значение будет 1, а если отжата, то 0. Используя эту функцию, наша программа может быть записана в таком виде:
while 1: for event in pygame.event.get(): if event.type == pygame.
QUIT: exit() keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= speed elif keys[pygame.
K_RIGHT]: x += speed sc.fill(WHITE) pygame.draw.
rect(sc, BLUE, (x, y, 10, 20)) pygame.display.update() clock.
tick(FPS)
Как видите, все стало предельно простым. Фактически, функция get_pressed() дает маску нажатых на клавиатуре клавиш и никак не влияет на состояния событий, находящихся в очереди. То есть, мы здесь напрямую не работаем с событиями, зарегистрированные в PyGame, а просто используем информацию о том, какая клавиша нажата.
И это имеет свои следствия. Например, если мы хотим перемещать прямоугольник при одновременном нажатии на клавишу Ctrl и курсорные клавиши вправо-влево, то с помощью функции get_pressed() нельзя отследить состояния клавиш-модификаторов: Shift, Ctrl, Alt и др. В выходном кортеже информации по ним просто нет. Здесь без обработки событий не обойтись. И лучше всего это сделать вот так:
move = 0 while 1: for event in pygame.event.get(): if event.type == pygame.
QUIT: exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT and event.
mod == pygame.KMOD_LCTRL: move = -speed elif event.key == pygame.K_RIGHT and event.mod == pygame.KMOD_LCTRL: move = speed elif event.
type == pygame.KEYUP: if event.key in [pygame.K_LEFT, pygame.K_RIGHT]: move = 0 x += move sc.
fill(WHITE) pygame.draw.rect(sc, BLUE, (x, y, 10, 20)) pygame.display.
update() clock.tick(FPS)
При этом важна последовательность нажатия на клавиши: сначала нужно нажать левый Ctrl, а потом курсорную клавишу вправо-влево. В другой последовательности работать уже не будет.
Библиотека PyGame обрабатывает такие клавиши-модификаторы несколько иначе стандартных клавиш, отсюда и получаются такие особенности. Вот так в целом выполняется обработка событий от клавиатуры. На следующем занятии мы рассмотрим обработку событий от мыши.
Источник: proproprogs.ru
PyGame. Введение
Довелось мне как-то пообщаться с этой библиотекой, чем и хотелось бы поделиться с вами, и себе зарубочку оставить, дабы не забывать:) В этом небольшом, надеюсь, посте, я на наглядном примере, опуская некоторые самые-самые теоретические основы (которые изложены в документации), покажу базовые принципы работы с библиотекой.
Задача.
Создать «игровое» пространство, в котором, при помощи клавиш-стрелок, можно будет перемещать объект.
Теория.
Прежде чем выкладывать листинги, остановлюсь на используемых методах из модулей библиотеки, описание которых взято из оф. документации.
Модуль image
1. pygame.image.load (filename): return Surface
Как можно догадаться, функция загружает некоторое изображение, и возвращеает в виде поверхности, типа, с которым при помощи функций pygame уже можно выполнять какие-либо операции (трансформировать, перемащать, удалять и пр.)
Модуль Surface
2. Surface.blit (source, dest, area=None, special_flags = 0)
Отрисовывает заданную поверхность (source) поверх базовой (Surface), где dest — кортеж (x, y), кординат отрисвоки, area — (width, height) — размеры source поверхности. На счет флагов, если честно пока не разбирался))
3. Surface.get_rect ()
Возвращет кортеж вида (x, y, width, height), где x, y — кординаты левого верхнего угла поверхности (Surface), width, height — соответственно ее размеры.
Модуль event
Он позволяет взаимодействовать с событиями и запросами. Иными словами, любое событие в pygame, нажатие клавиши например, помещается в список, состоящий из Event objects. Все эти «событийные объекты» имеют тип, получить доступ к которому можно путем Event.type.
4. pygame.event.get ()
Метод get () позволяет получить список событий.
Модуль Rect
Модуль для работы с кортежами типа rect.
5. Rect.move (X, Y)
Возвращает новый rect, в котором координаты смещены, относительно исходных, на заданные X, Y, в качестве которых может быть положительное или отрицательное целое число.
Практика.
Взяв на вооружение вышесказанное, получаем:
- # -*- coding: cp1251 -*-
- # Пример реализации движения при помощи pygame.
- from pygame import *
- import sys
- # Инициализируем загруженную библиотеку.
- init ( )
- # Создаем окно разрешением 640х480
- screen = display. set_mode ( ( 640 , 480 ) )
- # Устанавливаем название окна
- display. set_caption ( ‘example’ )
- # Загружаем фоновый рисунок, в формате:
- # jpg, png, gif(без анимации), bmp, pcx, tga(без сжатия), tif.
- background = image. load ( ‘background.bmp’ )
- # Отрисовываем рисунок в нашем окне
- screen. blit ( background, ( 0 , 0 ) )
- # Создаем игровой объект
- class GameObj:
- def __init__ ( self , img, x, y, step ) :
- self . img = img # Картинка объекта
- self . x = x # x, y — коодинаты начального положения
- self . y = y
- self . step = step # Шаг, на который будет смещаться объкт
- self . pos = img. get_rect ( ) . move ( x, y )
- def _move ( self , event ) :
- if event. key == K_UP: #273 код клавиши вверх
- self . pos = self . pos . move ( 0 , — self . step )
- if event. key == K_DOWN:
- self . pos = self . pos . move ( 0 , self . step )
- if event. key == 276 :
- self . pos = self . pos . move ( — self . step , 0 )
- if event. key == 275 :
- self . pos = self . pos . move ( self . step , 0 )
- avatar = image. load ( ‘player.bmp’ )
- # Инициируем игровой объект
- x = GameObj ( avatar, 320 , 220 , 10 )
- # Рисуем картинку объекта, в его координатах
- screen. blit ( x. img , x. pos )
- # Запускаем бесконечный цикл, чтобы окно не схлопнулось после появления 🙂
- while 1 :
- for i in event. get ( ) : # Перебор в списке событий
- if i. type == QUIT: # Обрабатываем событие шечка по крестику закрытия окна
- sys . exit ( )
- if i. type == KEYDOWN:
- screen. blit ( background, x. pos , x. pos )
- x._move ( i )
- screen. blit ( x. img , x. pos )
- # Обновляем изображение в окне, чтобы изменения в нем стали видны
- display. flip ( )
Послесловие.
Собственно вот и все, коротко и сердито:) Полистав огромное колл-во игр, выложенных на оф. сайте, и обнаружив там настоящие 3д поделки — удивился и возрадовался одновременно)) Хоть я и не собираюсь покорять игродельческие вершины, но приятно, что любимый язык настолько многомерен. Если кому-то будет интересна эта тема, и у меня не пропадет желание записывать — то непременно будет продолжение).
Источник: habr.com
pygame.event
Pygame обрабатывает все сообщения о событиях через очередь событий. Подпрограммы в этом модуле помогут вам управлять этой очередью событий. Очередь ввода сильно зависит от модуля pygame.display . Если дисплей не был инициализирован и видеорежим не установлен, очередь событий может работать неправильно. Подсистема событий должна вызываться из основного потока. Если вы хотите отправлять события в очередь из других потоков, используйте модуль pygame.fastevent .
Очередь событий имеет верхний предел количества событий, которые она может удерживать (128 для стандартного SDL 1.2). Когда очередь заполняется, новые события незаметно отбрасываются. Чтобы предотвратить потерю событий, особенно событий ввода, которые сигнализируют о команде выхода, ваша программа должна обрабатывать события каждый кадр (с помощью pygame.event.get() , pygame.event.pump() , pygame.event.wait() , pygame.event.peek() или pygame.event.clear() ) и обработать их. Отсутствие обработки событий может привести к тому, что ваша система решит, что ваша программа заблокирована. Чтобы ускорить обработку очереди, используйте pygame.event.set_blocked() чтобы ограничить, какие события помещаются в очередь.
Чтобы получить состояние различных устройств ввода, вы можете отказаться от очереди событий и получить доступ к устройствам ввода напрямую с помощью соответствующих модулей: pygame.mouse , pygame.key и pygame.joystick . Если вы используете этот метод, помните, что pygame требует некоторой формы связи с системным оконным менеджером и другими частями платформы. Чтобы pygame синхронизировался с системой, вам нужно будет вызвать pygame.event.pump() чтобы все оставалось актуальным. Обычно это нужно вызывать один раз за игровой цикл. Примечание. Джойстики не отправляют никаких событий, пока устройство не будет инициализировано.
Очередь событий содержит pygame.event.EventType событий pygame.event.EventType . Есть множество способов получить доступ к событиям в очереди, от простой проверки существования событий до их извлечения непосредственно из стека. Очередь событий также предлагает простую фильтрацию, которая может немного повысить производительность, блокируя определенные типы событий из очереди. Используйте pygame.event.set_allowed() и pygame.event.set_blocked() чтобы изменить эту фильтрацию. По умолчанию все типы событий могут быть помещены в очередь.
Все экземпляры pygame.event.EventType содержат идентификатор типа события и атрибуты, относящиеся к этому типу события. Идентификатор типа события доступен как свойство pygame.event.EventType.type . К любому из атрибутов, связанных с событием, можно получить доступ через pygame.event.EventType.__dict__ или напрямую как атрибут объекта события (поскольку поиск элементов передается в значения словаря объекта). У объекта события нет функций метода. Пользователи могут создавать свои собственные новые события с помощью функции pygame.event.Event() .
Идентификатор типа события находится между значениями NOEVENT и NUMEVENTS . Пользовательские события должны иметь значение в диапазоне от USEREVENT до NUMEVENTS — 1 . Рекомендуется, чтобы все пользовательские события следовали этой системе.
Мероприятия поддерживают сравнения в области равенства и неравенства.Два события равны,если они одного типа и имеют одинаковые значения атрибутов.
Во время отладки и экспериментов вы можете распечатать объект события для быстрого отображения его типа и членов. Функцию pygame.event.event_name() можно использовать для получения строки, представляющей имя типа события.
События,которые приходят из системы,будут иметь гарантированный набор атрибутов участников в зависимости от типа.Ниже приведен список типов событий со специфическими атрибутами.
QUIT none ACTIVEEVENT gain, state KEYDOWN key, mod, unicode, scancode KEYUP key, mod MOUSEMOTION pos, rel, buttons MOUSEBUTTONUP pos, button MOUSEBUTTONDOWN pos, button JOYAXISMOTION joy (deprecated), instance_id, axis, value JOYBALLMOTION joy (deprecated), instance_id, ball, rel JOYHATMOTION joy (deprecated), instance_id, hat, value JOYBUTTONUP joy (deprecated), instance_id, button JOYBUTTONDOWN joy (deprecated), instance_id, button VIDEORESIZE size, w, h VIDEOEXPOSE none USEREVENT code
Изменено в pygame 2.0.0: атрибут joy устарел, добавлен instance_id .
Вы также можете найти список констант для клавиш клавиатуры здесь .
В MacOSX, когда файл открывается с помощью приложения pygame, создается USEREVENT с атрибутом code , установленным на pygame.USEREVENT_DROPFILE . Существует дополнительный атрибут с именем filename ,в котором хранится имя файла, к которому осуществляется доступ.
USEREVENT code=pygame.USEREVENT_DROPFILE, filename
Новое в пигаме 1.9.2.
При компиляции с SDL2,pygame имеет эти дополнительные события и их атрибуты.
AUDIODEVICEADDED which, iscapture AUDIODEVICEREMOVED which, iscapture FINGERMOTION touch_id, finger_id, x, y, dx, dy FINGERDOWN touch_id, finger_id, x, y, dx, dy FINGERUP touch_id, finger_id, x, y, dx, dy MOUSEWHEEL which, flipped, x, y MULTIGESTURE touch_id, x, y, pinched, rotated, num_fingers TEXTEDITING text, start, length TEXTINPUT text WINDOWEVENT event
Новое в пигаме 1.9.5.
pygame может распознавать текст или файлы, помещенные в его окно. Если файл отброшен, file будет его путем. DROPTEXT событие поддерживается только на X11.
DROPBEGIN DROPCOMPLETE DROPFILE file DROPTEXT text
Новое в пигаме 2.0.0.
События, зарезервированные для использования pygame.midi .
MIDIIN MIDIOUT
Новое в пигаме 2.0.0.
SDL2 поддерживает горячее подключение контроллеров:
CONTROLLERDEVICEADDED device_index JOYDEVICEADDED device_index CONTROLLERDEVICEREMOVED instance_id JOYDEVICEREMOVED instance_id CONTROLLERDEVICEREMAPPED instance_id
Также в этой версии атрибуты instance_id были добавлены к событиям джойстика, а атрибут joy устарел.
Новое в пигаме 2.0.0.
pygame.event.pump()
обработчики внутриигровых событий
насос () -> Нет
Для каждого кадра вашей игры вам нужно будет сделать какой-то вызов очереди событий. Это гарантирует, что ваша программа может внутренне взаимодействовать с остальной частью операционной системы. Если вы не используете другие функции событий в своей игре, вам следует вызвать pygame.event.pump() чтобы позволить pygame обрабатывать внутренние действия.
В этой функции нет необходимости, если ваша программа постоянно обрабатывает события в очереди с помощью других функций pygame.event .
Есть важные вещи,которые должны быть решены внутри очереди на мероприятия.Главное окно может потребоваться перекрасить или ответить системе.Если вы не можете сделать вызов очереди событий слишком долго,система может решить,что ваша программа заблокирована.
Эту функцию следует вызывать только в потоке, который инициализировал pygame.display .
pygame.event.get()
получать события из очереди
get (eventtype = None) -> Список событий
get (eventtype = None, pump = True) -> Список событий
Это позволит получить все сообщения и удалить их из очереди.Если задан тип или последовательность типов,то из очереди будут удалены только эти сообщения.
Если вы берете из очереди только определенные события,имейте в виду,что в конечном итоге очередь может заполниться событиями,которые вас не интересуют.
Если pump имеет значение True (по умолчанию), тогда будет pygame.event.pump() .
Изменено в pygame 1.9.5: добавлен аргумент pump
pygame.event.poll()
получить одно событие из очереди
poll () -> экземпляр EventType
Возвращает одно событие из очереди. Если очередь событий пуста, pygame.NOEVENT будет возвращено событие типа pygame.NOEVENT . Возвращенное событие удаляется из очереди.
Эту функцию следует вызывать только в потоке, который инициализировал pygame.display .
pygame.event.wait()
ждать одного события из очереди
wait () -> экземпляр EventType
ждать (тайм-аут) -> экземпляр EventType
Возвращает одно событие из очереди. Если очередь пуста, эта функция будет ждать, пока она не будет создана. Начиная с pygame 2.0.0, если указан аргумент timeout , функция вернет событие типа pygame.NOEVENT , если никакие события не поступят в очередь за время timeout миллисекундах. Событие удаляется из очереди после того, как оно было возвращено.
Пока программа ожидает, она будет спать в состоянии ожидания. Это важно для программ, которые хотят использовать систему совместно с другими приложениями.
Изменено в pygame 2.0.0.dev13: Добавлен аргумент timeout
Эту функцию следует вызывать только в потоке, который инициализировал pygame.display .
pygame.event.peek()
проверить,ожидают ли типы событий в очереди.
peek(eventtype=None) -> bool
peek(eventtype=None, pump=True) -> bool
Возвращает True , если в очереди ожидают какие-либо события данного типа. Если передана последовательность типов событий, это вернет True , если какое-либо из этих событий находится в очереди.
Если pump имеет значение True (по умолчанию), тогда будет pygame.event.pump() .
Изменено в pygame 1.9.5: добавлен аргумент pump
pygame.event.clear()
удалять все события из очереди
clear(eventtype=None) -> None
clear(eventtype=None, pump=True) -> None
Удаляет все события из очереди. Если eventtype , удаляет данное событие или последовательность событий. Это имеет тот же эффект, что и pygame.event.get() за исключением того, что возвращается None . Это может быть немного более эффективным при очистке полной очереди событий.
Если pump имеет значение True (по умолчанию), тогда будет pygame.event.pump() .
Изменено в pygame 1.9.5: добавлен аргумент pump
pygame.event.event_name()
получить имя строки из идентификатора события
имя_события (тип) -> строка
Возвращает строку,представляющую имя (в стиле CapWords)данного типа события.
«UserEvent» возвращается для всех значений в диапазоне идентификаторов пользовательских событий. «Неизвестно» возвращается, если тип события не существует.
контролировать,какие события разрешены в очереди
set_blocked (тип) -> Нет
set_blocked (список типов) -> Нет
set_blocked (Нет) -> Нет
Данные типы событий не допускаются к отображению в очереди событий.По умолчанию все события могут быть помещены в очередь.Безопасно многократно отключать тип события.
Если None передается в качестве аргумента, ВСЕ типы событий блокируются от помещения в очередь.
контролировать,какие события разрешены в очереди
set_allowed (тип) -> Нет
set_allowed (список типов) -> Нет
set_allowed (Нет) -> Нет
Данные типы событий разрешены для отображения в очереди событий.По умолчанию в очередь могут быть помещены все типы событий.Безопасно включить тип события несколько раз.
Если в качестве аргумента передается None , ВСЕ типы событий могут быть помещены в очередь.
проверить,заблокирован ли тип события из очереди
get_blocked (тип) -> bool
get_blocked (список типов) -> bool
Возвращает True , если данный тип события заблокирован в очереди. Если передана последовательность типов событий, это вернет True , если какой-либо из этих типов событий заблокирован.
контролировать совместное использование устройств ввода с другими приложениями
set_grab (bool) -> Нет
Когда ваша программа работает в оконной среде, она будет совместно использовать мышь и клавиатуру с другими приложениями, у которых есть фокус. Если ваша программа устанавливает для захвата события значение True , она блокирует весь ввод в вашу программу.
Лучше не всегда захватывать входные данные,так как это мешает пользователю делать другие вещи в своей системе.
проверить,совместно ли программа использует устройства ввода
get_grab() -> bool
Возвращает True , когда входные события захватываются для этого приложения.
ставить в очередь новое событие
сообщение (Событие) -> Нет
Размещает данное событие в конце очереди событий.
Обычно это используется для помещения событий pygame.USEREVENT в очередь. Хотя может быть размещен любой тип события, если вы используете системные типы событий, ваша программа должна обязательно создать стандартные атрибуты с соответствующими значениями.
Если очередь событий заполнена, возникает pygame.error .