Доброго времени суток, уважаемые участники ресурса GcUp! В этой статье рассмотрим события в PyGame.
Перед изучением статьи читатель должен знать следующие вещи:
Знание синтаксиса и семантики языка Python ветки 2.х. (Если знаете С/С++, Java, PHP и т.д но не знаете Python то лучше не начинать изучать эти статьи, это разные языки и ничего общего у Python’a с ними нет).
Знание основ работы в IDLE(Python GUI) или умение запускать и редактировать программы на языке Python в других средах разработки.
Знание основных типов данных языка Python ветки 2.х. (числа, строки, последовательности/списки, словари, кортежи).
Умение работать в операционной системе Windows.
Знание информации, которая выложена в предыдущих статьях.
Логически эта статья будет разделена на следующие блоки:
Введение в события PyGame.
Анализ методов для работы над очередью событий в PyGame.
Заключение На этом все, приступим к изучению библиотеки PyGame.
Часть первая. Введение в события.
Все события в PyGame при их появлении сразу же добавляются в очередь событий. Очередь событий это обычный стек со структурой “последний вошел - первый вышел”. В модуле Event определенные некоторые методы для управления очередью событий, вот весь список методов и их короткое описание:
pygame.event.pump – обработка внутренних событий PyGame
pygame.event.get – Получить все события из очереди событий.
pygame.event.poll – Получить одно событие из очереди событий.
pygame.event.wait - Ждать первого события в очереди.
pygame.event.peek – Узнать находится ли событие в очереди.
pygame.event.clear – Удалить все события в очереди.
pygame.event.event_name – Получить имя события.
pygame.event.set_blocked – Заблокировать события для доступа в очередь.
pygame.event.set_allowed – Дать доступ событиям на добавление в очередь.
pygame.event.get_blocked – Узнать какие события заблокированы.
pygame.event.set_grab – Разрешить другим приложениям использовать устройства ввода.
pygame.event.get_grab – Узнать можно ли другим приложениям использовать устройства ввода.
pygame.event.post – Добавить событие в очередь.
pygame.event.Event –Создать новое событие.
Очередь событий зависит от модуля Display, если дисплей не был инициализирован и видео режим не установлен, очередь событий будет некорректно работать. Если приложение использует джойстик, то события связанные с этим устройством будут добавляться в очередь только после инициализации этого устройства. Программа на PyGame должна принять меры по сохранению очереди от переполнения, при переполнении возникает исключение. Объект Event содержит идентификатор типа события и доступные только для чтения данные, которые определяются по типу события. Идентификатор типа события содержится в свойстве Event.type, а набор атрибутов данных можно получить через метод Event.dict. События поддерживают сравнение на равенство. Два события равны, если они одного типа и имеют одинаковое значение атрибута. Ниже описана таблица с набором типов событий и их атрибутов данных:
QUIT - none
ACTIVEEVENT - gain, state
KEYDOWN - unicode, key, mod
KEYUP - key, mod
MOUSEMOTION - pos, rel, buttons
MOUSEBUTTONUP - pos, button
MOUSEBUTTONDOWN - pos, button
JOYAXISMOTION - joy, axis, value
JOYBALLMOTION - joy, ball, rel
JOYHATMOTION - joy, hat, value
JOYBUTTONUP - joy, button
JOYBUTTONDOWN - joy, button
VIDEORESIZE - size, w, h
VIDEOEXPOSE - none
USEREVENT – code
Теперь приступим к изучению методов для работы над очередью событий.
Часть вторая. Анализ методов для работы над очередью событий в PyGame.
Первым методом будет pygame.event.get(): return Eventlist, где Eventlist – список объектов Event. Этот метод представлен в трех реализациях:
pygame.event.get(): return Eventlist
pygame.event.get(type): return Eventlist
pygame.event.get(typelist): return Eventlist
Первая реализация не имеет параметров и возвращает список всех объектов Event из очереди. Во втором методе есть параметр type – тип события, если использовать этот вариант метода, то список будет содержать только объекты Event, тип которых будет равен параметру type. Третий вариант метода принимает список типов событий, этот метод возвратит все объекты Event, тип которых равен типам, указанных в параметре метода. Этот метод мы уже использовали в шаблоне программы на PyGame, вот кусок кода этого шаблона:
Code
for event in pygame.event.get():
Как видно для того чтобы пройтись по всему списку объектов возвращенных методом pygame.event.get мы ввели итератор event. В теле цикла мы можем сравнивать тип события и таким образом можем обрабатывать связанные с этим типом события. Для примера давайте обработаем тип события MOUSEBUTTONDOWN. Для начала откроем созданный нами раньше шаблон pygame_template.py и сохраним его под именем pygame_event.py и изменим значение заголовка окна на “PyGame Event”. Теперь надо разобраться с тем как мы будем обрабатывать событие, из названия MOUSEBUTTONDOWN понятно, то, что это событие связано с нажатием кнопки мыши, для обработки этого события мы будем рисовать красный круг там, где пользователь нажал левую кнопку мыши, для этого введем три переменные: circle_radius – радиус круга, circle_color – цвет круга, circle_pos – позиция центра круга, для этого в блоке инициализации пишем следующих код:
Теперь в телецикла с итератором event надо сравнить тип события с MOUSEBUTTONDOWN, если тип события равен MOUSEBUTTONDOWN то этого события есть атрибут button, теперь уже надо сравнить этот атрибут к значением левой кнопки мыши, левая кнопка мыши имеет значение 1, если значение атрибута button равно 1, то можно присвоить переменной circle_pos значение атрибута позиции мыши pos, вот весь код обработки события MOUSEBUTTONDOWN:
Code
if event.type == MOUSEBUTTONDOWN: if event.button == 1: circle_pos = event.pos
Осталось только нарисовать круг в блоке формирования кадра, рисовать круг будет методом pygame.draw.circle, этот метод мы с вами уже разобрали в предыдущей статье, собственно вот весь код формирования кадра:
Теперь можно запустить код и проверить что получилось. Как видно круг красного цвета рисуется на том месте, где пользователь последний раз нажал левую кнопку мыши.
Ну а теперь давайте обработаем событие, связанное с клавиатурой, давайте обработаем тип события KEYDOWN, давайте сделаем, так что при нажатии на клавишу “Esc” программа закрывалась. Первое что нам надо это узнать является ли событие типа KEYDOWN, в блоке цикла с итератором event пишем:
Code
if event.type == KEYDOWN:
Условие готово, осталось только сравнить атрибут key с клавишей “Esc”, код этой клавиши в PyGame равен константе “K_ESCAPE” (набор всех констант клавиш можно узнать в модуле Key), если атрибут key равен “K_ESCAPE” то снимаем флаг mainLoop, если этот фланг не установлен то программа закроется, вот код из блока предыдущего условия:
Code
if event.key == K_ESCAPE: mainLoop = False
Теперь можно проверить обрабатывается ли событие или нет, запускаем программу, как видно если нажать на клавишу “Esc” то программа закроется, а это значит то, что все работает хорошо. Следующий метод работы над очередью событий это pygame.event.set_blocked, этот метод блокирует добавление событий определенного типа в очередь событий. Он имеет следующие реализации:
pygame.event.set_blocked(type): return None
pygame.event.set_blocked(typelist): return None
pygame.event.set_blocked(None): return None Все три реализации возвращают None, то есть ничего не возвращают. В первой реализации используется параметр type, это тип события, добавление которого запрещено в очередь. Во второй реализации используется список типов события – typelist, которым запрещено добавляться в очередь. Следующий вариант является противоположным по отношению к двум предыдущим если в параметре ничего не указано, то все типы события могут быть добавлены в очередь событий. По умолчанию если не использовать эти методы, добавление в очередь событий доступно всем типам событий. Давайте попробуем заблокировать какое-то событие, для примера давайте заблокирует событие, которые мы обрабатываем, это позволит узнать заблокировали ли мы событие или нет, выбор в этом случае упал на тип события MOUSEBUTTONDOWN, добавим следующий код в блок инициализации данных:
Code
pygame.event.set_blocked(MOUSEBUTTONDOWN)
Теперь можно проверить заблокировано событие или нет, запускаем и пробуем нажимать правую кнопку мыши, как видно ничего не происходит, код обработка события есть, но оно не обрабатывается, так как типа этого события нет в очереди событий. Давайте теперь проверим, как работает вторая реализация этого метода, передадим в этот метод список из двух элементов MOUSEBUTTONDOWN и KEYDOWN, изменим код выше на этот код:
По идеи этот метод должен заблокировать тип событий MOUSEBUTTONDOWN и KEYDOWN, то есть обработчик нажатий клавиш, и обработчик нажатий клавиш мыши работать не будет, давайте запустим программу и узнаем это. Действительно, нажатие на клавишу “Esc”, не дает ни какого результата, также нет и результата при нажатии на левую кнопку мыши. Мы уже рассмотрели метод, который блокирует добавление событий в очередь, давайте теперь рассмотрим метод, который разблокирует добавление событий в очередь - pygame.event.set_allowed, этот метод чем-то похож на предыдущий метод, он тоже имеет три реализации:
pygame.event.set_allowed(type): return None
pygame.event.set_allowed(typelist): return None
pygame.event.set_allowed(None): return None Тут практически ничего рассказывать, это полная копия метода pygame.event.set_blocked только выполняет все наоборот, параметры у него такие же, как и в первом методе, если параметра нет, то не один тип событий не может попасть в очередь событий. Давайте перейдем к практике и попробуем изменить нашу программу, пусть при нажатии на клавишу Space блокировалось или разблокировалось добавление событий MOUSEBUTTONDOWN. Для начала уберем код блокировки событий в блоке инициализации данных и вместо этого определим флаг блокировки/разблокировки события block_flag, вот его инициализация:
Code
block_flag = False
Теперь надо сравнить атрибут key с клавишей Space, сам блок обработки события KEYDOWN уже есть, теперь надо сравнить атрибут, так что пишем код в блоке обработки события KEYDOWN:
Code
if event.key == K_SPACE:
Далее следует присвоит флагу block_flag отрицание, то есть если флаг содержал значение True то теперь он будет содержать False и наоборот если содержал False то теперь будет содержать True:
Code
block_flag = not block_flag
Можно еще вывести в терминал интерпретатора данные строку, по которым можно узнать заблокировано событие или нет:
Code
print 'MOUSEBUTTONDOWN is block: ', block_flag
Теперь в зависимости от значения флага block_flag будем блокировать или разблокировать событие MOUSEBUTTONDOWN:
Code
if block_flag: pygame.event.set_blocked(MOUSEBUTTONDOWN) else: pygame.event.set_allowed(MOUSEBUTTONDOWN)
Ну а теперь настал момент проверки, запускаем, как видим все работает, жмем на Space и блокируем/разблокируем добавление события MOUSEBUTTONDOWN в очередь событий, в терминал интерпретатора также выводится информация о том заблокировано событие MOUSEBUTTONDOWN или нет. Давайте теперь рассмотрим метод, по которому мы можем узнать заблокирован тип события или нет, рассмотрим метод pygame.event.get_blocked(type): return bool, тут type – тип события, метод возвращает логическое значение в зависимости от того заблокировано событие или нет. Давайте используем его на практике, удалим следующий код, в котором выводим в терминал информацию о том, заблокировано событие или нет:
Code
print 'MOUSEBUTTONDOWN is block: ', block_flag
И заменим его на код с методом pygame.event.get_blocked:
Code
print 'MOUSEBUTTONDOWN is block: ', pygame.event.get_blocked(MOUSEBUTTONDOWN)
Запустим и протестируем, как видим ничего не произошло, а это хорошо и значит, то, что все работает как надо. В целом у нас должен получится следующий код в файле pygame_event.py:
Ну а теперь займемся методом pygame.event.pump. Этот метод используется в том случае, если не требуется писать обработчиков событий, например если мы проигрываем анимацию передвижения объекта с одного места в другое, то писать обработчики событий нет смысла, но если мы не будем очищать очередь событий или передавать эту очередь другим программам, то наша программа зависнет, так как выполняется бесконечный цикл. Для этого чтобы программа не зависла надо отправить очередь другим программам. На помощь нам приходит следующий метод pygame.event.pump. Этот метод ничего не принимает в качестве параметров и ничего не возвращает. Давайте попробуем этот метод на практике, открываем шаблон pygame_template.py и сохраняем его под именем pygame_event_1.py и поменяем заголовок окна на “PyGame Event”. Теперь настало время, удалить цикл, в котором итератор event проходит по всем событиям, возвращаемых методом pygame.event.get. Если сейчас запустить программу то она зависнет, попробуйте это сделать. Как видно программа действительно зависает, для того чтобы убрать завившею программу надо перезагрузить интерпретатор через меню “Shell”. Теперь давайте добавим место цикла метод pygame.event.pump:
Code
pygame.event.pump()
Сам метод pygame.event.pump(): return None используется для обработки внутренних событий PyGame, таких как обрисовка окна, взаимодействие программы с системными событиями и т.д. Если в программе используется любой метод работы над очередью событий модуля Event, то можно не использовать pygame.event.pump. Теперь запустим программу и посмотрим, зависает программа или нет, как видно не зависает, но выйти из программы не можем, для этого нам понадобится следующие два метода. Метод pygame.event.peek возвращает логическое значение в зависимости от того имеется тип события в очереди или нет, метод реализовать в двух реализациях:
pygame.event.peek(type): return bool
pygame.event.peek(typelist): return bool В первом используется параметр type – определяющий тип события, если тип этого события есть в очереди, то метод возвратит True. Во втором варианте параметр typelist – это список типов событий, если одно из этих событий есть в очереди, то метод вернет True. Следующий метод это pygame.event.clear, этот метод очищает очередь событий, метод реализован в трех реализациях:
pygame.event.clear(): return None
pygame.event.clear(type): return None
pygame.event.clear(typelist): return None Во всех реализациях метод ничего не возвращает, но имеет разные параметры. В первом случае, когда метод не имеет параметра, очищается полностью очередь. Во втором случае удаляются только события, тип которых соответствует параметру type. В третьем случае удаляются все события, которые входят в список типов typelist. Имея эти два метода, мы теперь можем обработать события выхода из программы. Вначале мы узнаем, есть ли событие QUIT в очереди событий, если есть, то выйдем из главного цикла, так же придется очистить очередь чтобы не допустить переполнения очереди, так что удаляем метод pygame.event.pump и пишем следующий код:
Code
if pygame.event.peek(QUIT): mainLoop = False pygame.event.clear()
Как видно из кода, мы вначале узнали, есть ли данный тип события в очереди, если он есть, то убираем флаг главного цикла, а после условия очищаем очередь, так как нам надо заботится о переполнении очереди. Можно запустить и проверить работает закрытие программы или нет. Как видно работает, в итоге должен быть написан следующий код в файле pygame_event1.py:
Теперь настало время разобрать методы которые очень редко используются для работы над очередью событий, первый метод это pygame.event.wait(). Этот метод представлен в одном экземпляре и ничего не возвращает. Сам метод дожидается, когда в очереди памяти будет хотя бы одно событие, если в очереди нет событий, то программа ждет, когда оно там появится, хоть программа и будет ждать, но она будет находиться в состояние простоя, это очень важно если программа должна делится процессорным временем с другими программами и системой. Следующий метод это pygame.event.event_name(type): return string, метод принимает в качестве параметра тип события и возвращает его название в качестве строки, по сути метод используется для отладки программ, когда требуется узнать строковое имя типа события. Теперь пришло время рассмотреть методы, которые работают с устройствами ввода, их всего два, pygame.event.set_grab(bool): return None и pygame.event.get_grab(): return bool. Первый метод pygame.event.set_grab(bool): return None используется для того чтобы разрешать/запрещать другим программа пользоваться устройствами ввода когда фокус программы стоит на вашей программе. Он имеет всего один логический параметр, если он установлен в True, то другим программам запрещено получать события связанные с устройствами ввода. Второй метод pygame.event.get_grab(): return bool возвращает логической значение исходя от того запрещено ли другим программам пользоваться устройствами ввода. Ну а теперь рассмотрим метод, который очень редко используется, это метод pygame.event.poll(): return Event, как уже понятно из его название метод возвращает последнее событие в очереди, если очередь пустая то возвращается событие с типом NOEVENT, все возвращенные события удаляются из очереди. Метод используется редко и только на этапе отладки программы. Ну и на последок, в PyGame можно создавать и свои события, для этого есть конструктор pygame.event.Event(type, dict): return Event, где type – тип события, dict – словарь с содержанием атрибут/значение. В целом он используется для создания событий пользователей и часто типом такого события является тип USEREVENT, но его можно использовать и для программного создания событий, которые связаны с устройствами ввода/вывода. Созданное событие можно поместить в очередь событий через метод pygame.event.post(Event): return None, где Event – объект событие. Этот метод вставляет в конец очереди событие, созданное программным или другим путем.
Часть третья. Заключение.
Вот и все, мы с вами рассмотрели все методы модуля Event библиотеки PyGame для работы над очередью событий в PyGame, в целом эта статья является введением в события и поэтому некоторые методы были с примерами, а некоторые без них. Ну а следующей статье мы разберем полностью модуль Rect . Если есть, вопросы или проблемы по статье обращайтесь ко мне в Л.С. Все всем пока, желаю удачи в геймдеве. Спасибо за внимание с вами был noTformaT.
P.S.
Если вы просто скопируете программный код с этой статьи то он возможно не запустится, связано это с тем что табуляций и пробелы в Python имеют определенный смысл. Если это произошло, и программа зависла, то требуется перезагрузить терминал интерпретатора открыв в терминале меню «Shell» и выбрав пункт «Restart Shell».
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:
Игровые объявления и предложения:
Если вас заинтересовал материал «Основы PyGame. Введение в события», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела.
Предлагаются такие схожие материалы:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.