Как создать кнопку в pygame
Перейти к содержимому

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

  • автор:

Кнопки в pygame

Подскажите пожалуйста как реализовать в pygame выделение кнопки при наведении на нее курсора? Пробовал сделать отслеживание позиции мыши event.type == pygame.MOUSEMOTION:,но что то у меня ничего не выходит
Мой класс Button:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
import pygame class Button: def __init__(self,path,text,x,y): self.size = [190,45] #Размер кнопки self.image_button = pygame.image.load(path) #Загружаем изображение исходной кнопки self.text = text #Текст кнопки self.x = x #Позиция х кнопки self.y = y #Позиция у кнопки self.rect_button = pygame.Rect(self.x,self.y,self.size[0],self.size[1]) #Прямоугольник для создания коллизии с курсором self.rect_image_button = self.image_button.get_rect() """Создание кнопки при нажатии на нее""" self.image_click = pygame.image.load("images/blue_button03.png") self.image_put_on_button = pygame.image.load("images/blue_button01.png") def create_button(self,settings,color): """Создает кнопку на экране""" text_button = settings.font_text.render(self.text,True,color) #Создаем изображение с текстом text_rect = text_button.get_rect() #Возвращаем прямоугольник который занимает текст text_rect.center = self.rect_image_button.center #Делаем текст посередине кнопки self.image_button.blit(text_button,text_rect) self.image_click.blit(text_button,text_rect) self.image_put_on_button.blit(text_button,text_rect) def draw_button(self,screen,control): #Рисует созданную кнопку на экране """Рисует кнопку в зависимости от флага,который берется из класса Control""" if self.rect_button.collidepoint(control.mouse_x,control.mouse_y) and control.flag == "CLICKED": screen.blit(self.image_click, (self.x, self.y)) #Если кликнули мышкой то рисуем кнопку нажатой elif control.flag == "NORMAL": screen.blit(self.image_button,(self.x,self.y)) #Если ничего не происходит,то рисуем обычную кнопку elif self.rect_button.collidepoint(control.mouse_x,control.mouse_y): screen.blit(self.image_put_on_button,(self.x,self.y))

Класс Control:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
import pygame from pygame.locals import * class Control: def __init__(self): self.play = True #Переменная для остановки основного цикла игры self.mouse_x = 0 #Позиция х курсора self.mouse_y = 0 #Позиция у курсора self.flag = "NORMAL" #Флаг для отрисовки кнопок def control_game(self): """Все управление игрой""" for event in pygame.event.get(): if event.type == QUIT: self.play = False elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.play = False elif event.type == MOUSEBUTTONDOWN: self.mouse_x,self.mouse_y = pygame.mouse.get_pos() self.flag = "CLICKED" elif event.type == MOUSEBUTTONUP: self.flag = "NORMAL"

Создание игр на Python 3 и Pygame: Часть 4

Это четвёртая из пяти частей туториала, посвящённого созданию игр с помощью Python 3 и Pygame. В третьей части мы углубились в сердце Breakout и узнали, как обрабатывать события, познакомились с основным классом Breakout и увидели, как перемещать разные игровые объекты.

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

Распознавание коллизий

В играх объекты сталкиваются друг с другом, и Breakout не является исключением. В основном с объектами сталкивается мяч. В методе handle_ball_collisions() есть встроенная функция под названием intersect() , которая используется для проверки того, ударился ли мяч об объект, и того, где он столкнулся с объектом. Она возвращает ‘left’, ‘right’, ‘top’, ‘bottom’ или None, если мяч не столкнулся с объектом.

def handle_ball_collisions(self): def intersect(obj, ball): edges = dict( left=Rect(obj.left, obj.top, 1, obj.height), right=Rect(obj.right, obj.top, 1, obj.height), top=Rect(obj.left, obj.top, obj.width, 1), bottom=Rect(obj.left, obj.bottom, obj.width, 1)) collisions = set(edge for edge, rect in edges.items() if ball.bounds.colliderect(rect)) if not collisions: return None if len(collisions) == 1: return list(collisions)[0] if 'top' in collisions: if ball.centery >= obj.top: return 'top' if ball.centerx < obj.left: return 'left' else: return 'right' if 'bottom' in collisions: if ball.centery >= obj.bottom: return 'bottom' if ball.centerx < obj.left: return 'left' else: return 'right'

Столкновение мяча с ракеткой

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

Но если он ударяется о боковую часть ракетки, то отскакивает в противоположную сторону (влево или вправо) и продолжает движение вниз, пока не столкнётся с полом. В коде используется функция intersect() .

# Удар об ракетку s = self.ball.speed edge = intersect(self.paddle, self.ball) if edge is not None: self.sound_effects['paddle_hit'].play() if edge == 'top': speed_x = s[0] speed_y = -s[1] if self.paddle.moving_left: speed_x -= 1 elif self.paddle.moving_left: speed_x += 1 self.ball.speed = speed_x, speed_y elif edge in ('left', 'right'): self.ball.speed = (-s[0], s[1])

Столкновение с полом

Когда ракетка пропускает мяч на пути вниз (или мяч ударяется об ракетку сбоку), то мяч продолжает падать и затем ударяется об пол. В этот момент игрок теряет жизнь и мяч создаётся заново, чтобы игра могла продолжаться. Игра завершается, когда у игрока заканчиваются жизни.

# Удар об пол if self.ball.top > c.screen_height: self.lives -= 1 if self.lives == 0: self.game_over = True else: self.create_ball()

Столкновение с потолком и стенами

Когда мяч ударяется об стены или потолок, он просто отскакивает от них.

# Удар об потолок if self.ball.top < 0: self.ball.speed = (s[0], -s[1]) # Удар об стену if self.ball.left < 0 or self.ball.right >c.screen_width: self.ball.speed = (-s[0], s[1])

Столкновение с кирпичами

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

Чтобы определить, что мяч ударился об кирпич, код проверят, пересекается ли какой-нибудь из кирпичей с мячом:

# Удар об кирпич for brick in self.bricks: edge = intersect(brick, self.ball) if not edge: continue self.bricks.remove(brick) self.objects.remove(brick) self.score += self.points_per_brick if edge in ('top', 'bottom'): self.ball.speed = (s[0], -s[1]) else: self.ball.speed = (-s[0], s[1])

Программирование игрового меню

В большинстве игр есть какой-нибудь UI. В Breakout есть простое меню с двумя кнопками, 'PLAY' и 'QUIT'. Меню отображается в начале игры и пропадает, когда игрок нажимает на 'PLAY'. Давайте посмотрим, как реализуются кнопки и меню, а также как они интегрируются в игру.

Создание кнопок

В Pygame нет встроенной библиотеки UI. Есть сторонние расширения, но для меню я решил создать свои кнопки. Кнопка — это игровой объект, имеющий три состояния: нормальное, выделенное и нажатое. Нормальное состояние — это когда мышь не находится над кнопкой, а выделенное состояние — когда мышь находится над кнопкой, но левая кнопка мыши ещё не нажата. Нажатое состояние — это когда мышь находится над кнопкой и игрок нажал на левую кнопку мыши.

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

import pygame from game_object import GameObject from text_object import TextObject import config as c class Button(GameObject): def __init__(self, x, y, w, h, text, on_click=lambda x: None, padding=0): super().__init__(x, y, w, h) self.state = 'normal' self.on_click = on_click self.text = TextObject(x + padding, y + padding, lambda: text, c.button_text_color, c.font_name, c.font_size) def draw(self, surface): pygame.draw.rect(surface, self.back_color, self.bounds) self.text.draw(surface)

Кнопка обрабатывает собственные события мыши и изменяет своё внутреннее состояние на основании этих событий. Когда кнопка находится в нажатом состоянии и получает событие MOUSEBUTTONUP , это означает, что игрок нажал на кнопку, и вызывается функция on_click() .

def handle_mouse_event(self, type, pos): if type == pygame.MOUSEMOTION: self.handle_mouse_move(pos) elif type == pygame.MOUSEBUTTONDOWN: self.handle_mouse_down(pos) elif type == pygame.MOUSEBUTTONUP: self.handle_mouse_up(pos) def handle_mouse_move(self, pos): if self.bounds.collidepoint(pos): if self.state != 'pressed': self.state = 'hover' else: self.state = 'normal' def handle_mouse_down(self, pos): if self.bounds.collidepoint(pos): self.state = 'pressed' def handle_mouse_up(self, pos): if self.state == 'pressed': self.on_click(self) self.state = 'hover'

Свойство back_color , используемое для отрисовки фонового прямоугольника, всегда возвращает цвет, соответствующий текущему состоянию кнопки, чтобы игроку было ясно, что кнопка активна:

@property def back_color(self): return dict(normal=c.button_normal_back_color, hover=c.button_hover_back_color, pressed=c.button_pressed_back_color)[self.state]

Создание меню

Функция create_menu() создаёт меню с двумя кнопками с текстом 'PLAY' и 'QUIT'. Она имеет две встроенные функции, on_play() и on_quit() , которые она передаёт соответствующей кнопке. Каждая кнопка добавляется в список objects (для отрисовки), а также в поле menu_buttons .

def create_menu(self): for i, (text, handler) in enumerate((('PLAY', on_play), ('QUIT', on_quit))): b = Button(c.menu_offset_x, c.menu_offset_y + (c.menu_button_h + 5) * i, c.menu_button_w, c.menu_button_h, text, handler, padding=5) self.objects.append(b) self.menu_buttons.append(b) self.mouse_handlers.append(b.handle_mouse_event)

При нажатии кнопки PLAY вызывается функция on_play() , удаляющая кнопки из списка objects , чтобы они больше не отрисовывались. Кроме того, значения булевых полей, которые запускают начало игры — is_game_running и start_level — становятся равными True.

При нажатии кнопки QUIT is_game_running принимает значение False (фактически ставя игру на паузу), а game_over присваивается значение True, что приводит к срабатыванию последовательности завершения игры.

def on_play(button): for b in self.menu_buttons: self.objects.remove(b) self.is_game_running = True self.start_level = True def on_quit(button): self.game_over = True self.is_game_running = False

Отображение и сокрытие игрового меню

Отображение и сокрытие меню выполняются неявным образом. Когда кнопки находятся в списке objects , меню видимо; когда они удаляются, оно скрывается. Всё очень просто.

Можно создать встроенное меню с собственной поверхностью, которое рендерит свои подкомпоненты (кнопки и другие объекты), а затем просто добавлять/удалять эти компоненты меню, но для такого простого меню это не требуется.

Подводим итог

В этой части мы рассмотрели распознавание коллизий и то, что происходит, когда мяч сталкивается с разными объектами: ракеткой, кирпичами, стенами, полом и потолком. Также мы создали меню с собственными кнопками, которое можно скрывать и отображать по команде.

В последней части серии мы рассмотрим завершение игры, отслеживание очков и жизней, звуковые эффекты и музыку.

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

Создание класса 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?

Тут у меня задался вопрос, как сделать кнопку в pygame(без использования классов)?
Нууу и если вы кидаете ссылку на источник то пожалуйста не английский.

Голосование за лучший ответ

Валерий, понимаете, тут такая штука. -Я это делаю не из вредности!
1) Кнопка - это объект. Учите ООП. Без ООП вы себя очень ограничите в возможностях.
2) - Почти все нормальные программисты общаются на английском и не важно из какой они страны. И мануалы они пишут, тоже - на английском и изредка на своем национальном языке. Мне проще написать мануал для всех программистов мира, чем писать для пары сотен, если я выходец малых народов. - Понимаете?
Ради интереса - зайдите на: http://stackoverflow.com и http://stackoverflow.ru и сравните уровень вопросов и ответов. В итоге, на http://stackoverflow.com вы не найдете таких глупых вопросов т. к. они возникают только у того, кто не может прочитать на английском языке. Я понимаю, что сложно составить правильно фразу для вопроса, ну так вам и не надо. Вы просто переводите с помощью переводчика. Учите английский, если есть желание развиваться в данной деятельности.

По ссылке есть и исходники кнопки (естественно ООП, а куда без ООП?!)
И видео инструкция.
P.S. Зачем вам pygame, если вы еще не понимаете ООП?

Валерий МегрикянУченик (168) 7 лет назад
Один вопрос:
Что такое ООП?

Игорь Иванов Мастер (1568) Объектно-ориентированное программирование (в дальнейшем ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов. Объект — это сущность, экземпляр класса, которой можно посылать сообщения, и которая может на них реагировать, используя свои данные. Но прежде идет Объектно-ориентированное Проектирование. Объектно-ориентированное Проектирование - это дисциплина, описывающая способы (варианты) задания (определения) объектов и их взаимодействие для решения проблемы, которая определена и описана в ходе объектно-ориентированного анализа. Ну про анализ надеюсь не надо писать?

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

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