Перейти к содержимому

Как создать кнопку в pygame

  • автор:

События клавиатуры

Человек может управлять объектами в игре в основном с помощь клавиатуры, мыши, джойстика. Когда на «манипуляторах» что-то двигается или нажимается, то возникают события определенных типов. Обработкой событий занимается модуль pygame.event , который включает ряд функций, наиболее важная из которых уже ранее рассмотренная pygame.event.get() , которая забирает из очереди произошедшие события.

В pygame, когда фиксируется то или иное событие, создается соответствующий ему объект от класса Event . Уже с этими объектами работает программа. Экземпляры данного класса имеют только свойства, у них нет методов. У всех экземпляров есть свойство type . Набор остальных свойств события зависит от значения type .

События клавиатуры могут быть двух типов (иметь одно из двух значений type ) – клавиша была нажата, клавиша была отпущена. Если вы нажали клавишу и отпустили, то в очередь событий будут записаны оба. Какое из них обрабатывать, зависит от контекста игры. Если вы зажали клавишу и не отпускаете ее, то в очередь записывается только один вариант – клавиша нажата.

Событию типа «клавиша нажата» в поле type записывается числовое значение, совпадающее со значением константы pygame.KEYDOWN . Событию типа «клавиша отпущена» в поле type записывается значение, совпадающее со значением константы pygame.KEYUP .

У обоих типов событий клавиатуры есть атрибуты key и mod . В key записывается конкретная клавиша, которая была нажата или отжата. В mod – клавиши-модификаторы ( Shift , Ctrl и др.), которые были зажаты в момент нажатия или отжатия обычной клавиши. У событий KEYDOWN также есть поле unicode , куда записывается символ нажатой клавиши (тип данных str ).

Рассмотрим, как это работает. Пусть в центре окна имеется круг, который можно двигать по горизонтали клавишами стрелок клавиатуры:

import pygame import sys FPS = 60 W = 700 # ширина экрана H = 300 # высота экрана WHITE = (255, 255, 255) BLUE = (0, 70, 225) sc = pygame.display.set_mode((W, H)) clock = pygame.time.Clock() # координаты и радиус круга x = W // 2 y = H // 2 r = 50 while 1: for i in pygame.event.get(): if i.type == pygame.QUIT: sys.exit() elif i.type == pygame.KEYDOWN: if i.key == pygame.K_LEFT: x -= 3 elif i.key == pygame.K_RIGHT: x += 3 sc.fill(WHITE) pygame.draw.circle(sc, BLUE, (x, y), r) pygame.display.update() clock.tick(FPS) 

В цикле обработки событий теперь проверяется не только событие выхода, но также нажатие клавиш. Сначала необходимо проверить тип, потому что не у всех событий есть атрибут key . Если сразу начать проверять key , то сгенерируется ошибка по той причине, что могло произойти множество событий. Например, движение мыши, у которого нет поля key . Соответственно, попытка взять значение из несуществующего поля ( i.key ) приведет к генерации исключения.

Часто проверку и типа и клавиши записывают в одно логическое выражение ( i.type == pygame.KEYDOWN and i.key == pygame.K_LEFT ). В Python так можно делать потому, что если первая часть сложного выражения возвращает ложь, то вторая часть уже не проверяется.

Если какая-либо клавиша была нажата, то проверяется, какая именно. В данном случае обрабатываются только две клавиши. В зависимости от этого меняется значение координаты x .

Проблема данного кода в том, что при выполнении программы, чтобы круг двигался, надо постоянно нажимать и отжимать клавиши. Если просто зажать их на длительный период, то объект не будет постоянно двигаться. Он сместиться только один раз на 3 пикселя.

Так происходит потому, что событие нажатия на клавишу происходит один раз, сколь долго бы ее не держали. Это событие было забрано из очереди функцией get() и обработано. Его больше нет. Поэтому приходится генерировать новое событие, еще раз нажимая на клавишу.

Как быть, если по логике вещей надо, чтобы шар двигался до тех пор, пока клавиша зажата? Когда же она отпускается, шар должен останавливаться. Первое, что надо сделать, – это перенести изменение координаты x в основную ветку главного цикла while . В таком случае на каждой его итерации координата будет меняться, а значит шар двигаться постоянно.

Во-вторых, в цикле обработки событий нам придется следить не только за нажатием клавиши, но и ее отжатием. Когда клавиша нажимается, какая-либо переменная, играющая роль флага, должна принимать одно значение, когда клавиша отпускается эта же переменная должна принимать другое значение.

В основном теле while надо проверять значение этой переменной и в зависимости от него менять или не менять значение координаты.

import pygame import sys FPS = 60 W = 700 # ширина экрана H = 300 # высота экрана WHITE = (255, 255, 255) BLUE = (0, 70, 225) RIGHT = "to the right" LEFT = "to the left" STOP = "stop" sc = pygame.display.set_mode((W, H)) clock = pygame.time.Clock() # координаты и радиус круга x = W // 2 y = H // 2 r = 50 motion = STOP while 1: for i in pygame.event.get(): if i.type == pygame.QUIT: sys.exit() elif i.type == pygame.KEYDOWN: if i.key == pygame.K_LEFT: motion = LEFT elif i.key == pygame.K_RIGHT: motion = RIGHT elif i.type == pygame.KEYUP: if i.key in [pygame.K_LEFT, pygame.K_RIGHT]: motion = STOP sc.fill(WHITE) pygame.draw.circle(sc, BLUE, (x, y), r) pygame.display.update() if motion == LEFT: x -= 3 elif motion == RIGHT: x += 3 clock.tick(FPS) 

Использовать константы не обязательно, можно сразу присваивать строки или даже числа (например, motion = 1 обозначает движение вправо, -1 – влево, 0 – остановка). Однако константы позволяют легче понимать и обслуживать в дальнейшем код, делают его более информативным. Лучше привыкнуть к такому стилю.

Должно проверяться отжатие только двух клавиш. Если проверять исключительно KEYUP без последующей конкретизации, то отжатие любой клавиши приведет к остановке, даже если в это время будет по-прежнему зажиматься клавиша влево или вправо. Выражение i.key in [pygame.K_LEFT, pygame.K_RIGHT] обозначает, что если значение i.key совпадает с одним из значений в списке, то все выражение возвращает истину.

На самом деле существует способ по-проще. В библиотеке pygame с событиями работает не только модуль event . Так модуль pygame.key включает функции, связанные исключительно с клавиатурой. Здесь есть функция pygame.key.get_pressed() , которая возвращает кортеж двоичных значений. Индекс каждого значения соответствует своей клавиатурной константе. Само значение равно 1, если клавиша нажата, и 0 – если не нажата.

Эта функция подходит не для всех случаев обработки клавиатурных событий, но в нашем подойдет. Поэтому мы можем упростить код до такого варианта:

import pygame import sys FPS = 60 W = 700 # ширина экрана H = 300 # высота экрана WHITE = (255, 255, 255) BLUE = (0, 70, 225) sc = pygame.display.set_mode((W, H)) clock = pygame.time.Clock() # координаты и радиус круга x = W // 2 y = H // 2 r = 50 while 1: for i in pygame.event.get(): if i.type == pygame.QUIT: sys.exit() sc.fill(WHITE) pygame.draw.circle(sc, BLUE, (x, y), r) pygame.display.update() keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= 3 elif keys[pygame.K_RIGHT]: x += 3 clock.tick(FPS) 

Можно сказать, вызов get_pressed() снимает «маску» зажатых клавиш. Мы ее снимаем на каждой итерации главного цикла. Это даже не регистрация событий как таковых.

Выражение типа keys[pygame.K_LEFT] извлекает значение из кортежа по индексу, значение которого записано в константе K_LEFT . Если извлеченное значение True , то координата меняется.

Если необходимо, чтобы событие обрабатывалось при нажатии двух и более клавиш, то работает такое логическое выражение: keys[pygame.K_LEFT] and keys[pygame.K_a] (одновременное нажатие стрелки ‘влево’ и буквы ‘a’). Однако если нужно задействовать не обычные клавиши, а модификаторы, то данный номер не проходит.

В таком случае можно вернуться к первому варианту – перебирать события в цикле for :

. elif i.type == pygame.KEYDOWN: if i.key == pygame.K_LEFT and\ (i.mod & pygame.KMOD_SHIFT): motion = LEFT .

Здесь при if будет True , если перед нажатием стрелки был зажат левый Shift . Причем обратная последовательность: сначала зажать стрелку, потом Shift не сработает. Видимо модификаторы обрабатываются библиотекой pygame несколько отлично от обычных клавиш. Допустим, если при зажатии обычных клавиш генерируется только одно событие, то для модификаторов они генерируются постоянно или хранятся до отпускания в другой очереди.

Таким образом, если первым зажимается K_LEFT , то событие сразу обрабатывается. При этом в i.mod записывается отсутствие модификатора. Поэтому условие не срабатывает.

Если же первым зажимается модификатор, то это событие не теряется и позволяет условию при if выполнится в случае нажатия при этом обычной клавиши.

Весь перечень констант pygame, соответствующих клавишам клавиатуры, смотрите в документации: https://www.pygame.org/docs/ref/key.html

Практическая работа

Измените приведенную в уроке программу так, чтобы круг с той же скоростью, т. е. постепенно, возвращался назад в исходную точку, когда клавиша отпускается.

Курс с примерами решений практических работ:
pdf-версия

X Скрыть Наверх

Pygame. Введение в разработку игр на Python

Как сделать button в модуле pygame?

Как сделать в модуле pygame несколько кнопок? Чтобы при нажатии одной из кнопки сцена менялась? А при нажатии на другую кнопку сцена менялась на другую? Версия Python 3.1.

Отслеживать

задан 22 фев 2016 в 21:39

Ivan Kärme Ivan Kärme

63 1 1 золотой знак 2 2 серебряных знака 4 4 бронзовых знака

Если вам дан исчерпывающий ответ, отметьте его как верный (галка напротив выбранного ответа).

24 фев 2016 в 10:26

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Сайт создателя, там же ссылка на скачивание с примером: http://simonhl.dk/button-drawer-python-2-6/

# -*- coding: cp1252 -*- #/usr/bin/env python #Simon H. Larsen #Buttons #Project startet: d. 26. august 2012 import pygame from pygame.locals import * pygame.init() class Button: def create_button(self, surface, color, x, y, length, height, width, text, text_color): surface = self.draw_button(surface, color, length, height, x, y, width) surface = self.write_text(surface, text, text_color, length, height, x, y) self.rect = pygame.Rect(x,y, length, height) return surface def write_text(self, surface, text, text_color, length, height, x, y): font_size = int(length//len(text)) myFont = pygame.font.SysFont("Calibri", font_size) myText = myFont.render(text, 1, text_color) surface.blit(myText, ((x+length/2) - myText.get_width()/2, (y+height/2) - myText.get_height()/2)) return surface def draw_button(self, surface, color, length, height, x, y, width): for i in range(1,10): s = pygame.Surface((length+(i*2),height+(i*2))) s.fill(color) alpha = (255/(i+2)) if alpha self.rect.topleft[0]: if mouse[1] > self.rect.topleft[1]: if mouse[0] < self.rect.bottomright[0]: if mouse[1] < self.rect.bottomright[1]: print "Some button was pressed!" return True else: return False else: return False else: return False else: return False 

Создание класса Button

Так как в Pygame не существует встроенного метода создания кнопок, мы напишем класс Button для создания заполненного прямоугольника с текстовой надписью. Следующий код может использоваться для создания кнопок в любой игре. Ниже приведена первая часть класса Button; сохраните ее в файле button.py:

(1) . .def __init__(self, ai_settings, screen, msg):

. . . ."""Инициализирует атрибуты кнопки."""

. . . .# Назначение размеров и свойств кнопок.

(2) . . . .self.width, self.height = 200, 50

. . . .self.button_color = (0, 255, 0)

. . . .self.text_color = (255, 255, 255)

(3) . . . .self.font = pygame.font.SysFont(None, 48)

. . . .# Построение объекта rect кнопки и выравнивание по центру экрана.

(4) . . . .self.rect = pygame.Rect(0, 0, self.width, self.height)

. . . .# Сообщение кнопки создается только один раз.

Сначала программа импортирует модуль pygame.font, который позволяет Pygame выводить текст на экран. Метод __init__() получает параметры self, объекты ai_settings и screen, а также строку msg с текстом кнопки (1) . Размеры кнопки задаются в точке (2), после чего атрибуты button_color и text_color задаются так, чтобы прямоугольник кнопки был окрашен в ярко-зеленый цвет, а текст выводился белым цветом.

В точке (3) происходит подготовка атрибута font для вывода текста. Аргумент None сообщает Pygame, что для вывода текста должен использоваться шрифт по умолчанию, а значение 48 определяет размер текста. Чтобы выровнять кнопку по центру экрана, мы создаем объект rect для кнопки (4) и задаем его атрибут center в соответствии с одноименным атрибутом экрана.

Pygame выводит строку текста в виде графического изображения. В точке (5) эта задача решается методом prep_msg(). Код prep_msg() выглядит так:

def prep_msg(self, msg):

. ."""Преобразует msg в прямоугольник и выравнивает текст по центру."""

(1) . .self.msg_image = self.font.render(msg, True, self.text_color,

(2) . .self.msg_image_rect = self.msg_image.get_rect()

Метод prep_msg() должен получать параметр self и текст, который нужно вывести в графическом виде (msg). Вызов font.render() преобразует текст, хранящийся в msg, в изображение, которое затем сохраняется в msg_image (1) . Методу font.render() также передается логический признак режима сглаживания текста. В остальных аргументах передаются цвет шрифта и цвет фона. В нашем примере режим сглаживания включен (True), а цвет фона совпадает с цветом фона кнопки. (Если цвет фона не указан, Pygame пытается вывести шрифт с прозрачным фоном.)

В точке (3) изображение текста выравнивается по центру кнопки, для чего создается объект rect изображения, а его атрибут center приводится в соответствие с одноименным атрибутом кнопки.

Остается создать метод draw_button(), который может вызываться для отображения кнопки на экране:

. .# Отображение пустой кнопки и вывод сообщения.

Вызов метода screen.fill() рисует прямоугольную часть кнопки. Затем вызов screen.blit() выводит изображение текста на экран с передачей изображения и объекта rect, связанного с изображением. Класс Button готов.

Как создать кнопку в pygame

Python. PyGame. Ключи клавиатуры

Python. PyGame. Коды клавиш для программирования событий клавиатуры.

В библиотеке pygame для проверки нажатия конкретной клавиши используется ключ клавиши. Определить клавишу можно, проверив её код:
Например, pygame.key.get_pressed()[pygame.K_LEFT]

pygame Constant ASCII Description
K_BACKSPACE \b backspace
K_TAB \t tab
K_CLEAR clear
K_RETURN \r Клавиша Enter
K_PAUSE pause
K_ESCAPE ^[ Клавиша Esc
K_SPACE Клавиша Пробел
K_EXCLAIM ! exclaim
K_QUOTEDBL " quotedbl
K_HASH # hash
K_DOLLAR $ dollar
K_AMPERSAND & ampersand
K_QUOTE quote
K_LEFTPAREN ( left parenthesis
K_RIGHTPAREN ) right parenthesis
K_ASTERISK * asterisk
K_PLUS + plus sign
K_COMMA , comma
K_MINUS - minus sign
K_PERIOD . period
K_SLASH / forward slash
K_0 0 0
K_1 1 1
K_2 2 2
K_3 3 3
K_4 4 4
K_5 5 5
K_6 6 6
K_7 7 7
K_8 8 8
K_9 9 9
K_COLON : colon
K_SEMICOLON ; semicolon
K_LESS less-than sign
K_EQUALS = equals sign
K_GREATER > greater-than sign
K_QUESTION ? question mark
K_AT @ at
K_LEFTBRACKET [ left bracket
K_BACKSLASH \ backslash
K_RIGHTBRACKET ] right bracket
K_CARET ^ caret
K_UNDERSCORE _ underscore
K_BACKQUOTE ` grave
K_a a a
K_b b b
K_c c c
K_d d d
K_e e e
K_f f f
K_g g g
K_h h h
K_i i i
K_j j j
K_k k k
K_l l l
K_m m m
K_n n n
K_o o o
K_p p p
K_q q q
K_r r r
K_s s s
K_t t t
K_u u u
K_v v v
K_w w w
K_x x x
K_y y y
K_z z z
K_DELETE Клавиша delete на дополнительном поле
K_KP0 Клавиша 0 на дополнительном поле
K_KP1 Клавиша 1 на дополнительном поле
K_KP2 Клавиша 2 на дополнительном поле
K_KP3 Клавиша 3 на дополнительном поле
K_KP4 Клавиша 4 на дополнительном поле
K_KP5 Клавиша 5 на дополнительном поле
K_KP6 Клавиша 6 на дополнительном поле
K_KP7 Клавиша 7 на дополнительном поле
K_KP8 Клавиша 8 на дополнительном поле
K_KP9 Клавиша 9 на дополнительном поле
K_KP_PERIOD . Клавиша . на дополнительном поле
K_KP_DIVIDE / Клавиша / на дополнительном поле
K_KP_MULTIPLY * Клавиша * на дополнительном поле
K_KP_MINUS - Клавиша - на дополнительном поле
K_KP_PLUS + Клавиша + на дополнительном поле
K_KP_ENTER \r Клавиша Enter на дополнительном поле
K_KP_EQUALS = keypad equals
K_UP стрелка вверх
K_DOWN стрелка вниз
K_RIGHT стрелка вправо
K_LEFT стрелка влево
K_INSERT Клавиша insert
K_HOME Клавиша home
K_END Клавиша end
K_PAGEUP Клавиша page up
K_PAGEDOWN Клавиша page down
K_F1 Клавиша F1
K_F2 Клавиша F2
K_F3 Клавиша F3
K_F4 Клавиша F4
K_F5 Клавиша F5
K_F6 Клавиша F6
K_F7 Клавиша F7
K_F8 Клавиша F8
K_F9 Клавиша F9
K_F10 Клавиша F10
K_F11 Клавиша F11
K_F12 Клавиша F12
K_F13 Клавиша F13
K_F14 Клавиша F14
K_F15 Клавиша F15
K_NUMLOCK Клавиша numlock
K_CAPSLOCK Клавиша capslock
K_SCROLLOCK Клавиша scrollock
K_RSHIFT Правый shift
K_LSHIFT Левый shift
K_RCTRL Правый control
K_LCTRL Левый control
K_RALT Правый alt
K_LALT Левый alt
K_RMETA right meta
K_LMETA left meta
K_LSUPER left Windows key
K_RSUPER right Windows key
K_MODE mode shift
K_HELP help
K_PRINT Клавиша print screen (PrtSc)
K_SYSREQ sysrq
K_BREAK break
K_MENU menu
K_POWER power
K_EURO Euro

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *