обзор
Это третья часть серии из пяти уроков, посвященных созданию игр с Python 3 и Pygame. Во второй части мы рассмотрели класс TextObject используемый для визуализации текста на экране, создали главное окно и научились рисовать такие объекты, как кубики, шарик и весло.
В этой части мы погрузимся в сердце Breakout и узнаем, как обрабатывать события, познакомимся с основным классом Breakout и посмотрим, как перемещать различные игровые объекты.
Обработка событий
В Breakout есть три типа событий: события нажатия клавиш, события мыши и события таймера. Основной цикл в классе Game обрабатывает события нажатия клавиш и мыши и доставляет их подписчикам (вызывая функцию-обработчик).
Хотя класс Game очень универсален и не имеет специальных знаний для Breakout, сама подписка и способы обработки каждого события очень специфичны.
Breakout Class
Класс Breakout — это то, где управляется большая часть знаний об игре Breakout. В этой серии мы встретимся с классом Breakout несколько раз. Вот строки, которые регистрируют различные обработчики событий.
Обратите внимание, что все события клавиш для левой и правой клавиш со стрелками будут идти к одному и тому же методу-обработчику весла.
|
1
2
3
4
5
6
7
8
|
# Register the handle_mouse_event() method of a button object
self.mouse_handlers.append(b.handle_mouse_event)
# Register the handle() method of the paddle to handle key events
self.keydown_handlers[pygame.K_LEFT].append(paddle.handle)
self.keydown_handlers[pygame.K_RIGHT].append(paddle.handle)
self.keyup_handlers[pygame.K_LEFT].append(paddle.handle)
self.keyup_handlers[pygame.K_RIGHT].append(paddle.handle)
|
Обработка нажатия клавиш
Класс Game будет вызывать зарегистрированные обработчики для каждого ключевого события и передавать ключ. Обратите внимание, что это не класс Paddle. В Breakout единственным объектом, который заинтересован в этих событиях, является весло. Когда клавиша нажата или отпущена, вызывается метод handle() .
Paddle не нужно знать, было ли это событие нажатия клавиши key или up, потому что оно управляет текущим состоянием через пару логических переменных: moving_left и moving_right . Если moving_left равен True, это означает, что нажата левая клавиша со стрелкой, и следующее событие будет нажатием клавиши вверх, что отпустит его. То же самое касается правой клавиши со стрелкой. Логика так же проста, как переключение этих переменных в ответ на любое событие.
|
1
2
3
4
5
|
def handle(self, key):
if key == pygame.K_LEFT:
self.moving_left = not self.moving_left
else:
self.moving_right = not self.moving_right
|
Обработка событий мыши
В Breakout есть игровое меню, которое вы скоро встретите. Кнопка в меню обрабатывает различные события мыши, такие как движение и щелчки (события мыши и мыши). В ответ на эти события кнопка обновляет внутреннюю переменную состояния. Вот код обработки мыши:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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’
|
Обратите внимание, что метод handle_mouse_event() который зарегистрирован для получения событий мыши, проверяет тип события и передает его конкретному методу, который обрабатывает этот тип события.
Обработка событий таймера
События таймера не обрабатываются в основном цикле. Тем не менее, поскольку основной цикл вызывается каждый кадр, легко проверить, происходит ли определенное временное событие. Вы увидите пример этого позже при обсуждении временных эффектов.
Другая ситуация — когда мы хотим заморозить игру, например, при отображении сообщения, которое игрок должен прочитать без отвлечения. Метод show_message() класса Breakout использует этот подход и вызывает time.sleep() . Вот соответствующий код:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
import config as c
class Breakout(Game):
def show_message(self,
text,
color=colors.WHITE,
font_name=’Arial’,
font_size=20,
centralized=False):
message = TextObject(c.screen_width // 2,
c.screen_height // 2,
lambda: text, color,
font_name, font_size)
self.draw()
message.draw(self.surface, centralized)
pygame.display.update()
time.sleep(c.message_duration)
|
Игровой процесс
В части игрового процесса действуют правила Breakout (посмотрите, что я там делал?). Игровой процесс заключается в перемещении различных объектов в ответ на события и изменении состояния игры в зависимости от их взаимодействия.
Перемещение Весла
Ранее вы видели, что класс Paddle реагирует на клавиши со стрелками, обновляя свои moving_left и moving_right . Фактическое движение происходит в методе update() . Здесь происходит некоторое вычисление, если весло находится близко к левому или правому краю экрана. Мы не хотим, чтобы манипулятор перемещался за пределы экрана (включая предопределенное смещение).
Таким образом, если движение привело бы его к краю, код настраивает движение так, чтобы оно остановилось точно на краю. Поскольку весло движется только горизонтально, вертикальная составляющая движения всегда равна нулю.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import pygame
import config as c
from game_object import GameObject
class Paddle(GameObject):
def __init__(self, x, y, w, h, color, offset):
GameObject.__init__(self, x, y, w, h)
self.color = color
self.offset = offset
self.moving_left = False
self.moving_right = False
…
def update(self):
if self.moving_left:
dx = -(min(self.offset, self.left))
elif self.moving_right:
dx = min(self.offset, c.screen_width — self.right)
else:
return
self.move(dx, 0)
|
Перемещение мяча
Мяч просто использует функциональность базового класса GameObject , который перемещает игровые объекты в зависимости от их скорости (с горизонтальными и вертикальными компонентами). Скорость мяча определяется многими факторами в классе Breakout, которые вы скоро увидите. Поскольку перемещение — это просто добавление скорости к текущей позиции, направление движения шара полностью определяется его скоростью вдоль горизонтальной и вертикальной осей.
Установка начальной скорости мяча
Мяч в Breakout появляется из ниоткуда в начале игры каждый раз, когда игрок теряет жизнь. Он просто материализуется из эфира и начинает падать либо прямо вниз, либо под небольшим углом. Когда шар создается в create_ball() , он получает скорость со случайным горизонтальным компонентом между -2 и 2 и вертикальным компонентом, который определяется в модуле config.py (в настоящее время установлен на 3).
|
1
2
3
4
5
6
7
8
|
def create_ball(self):
speed = (random.randint(-2, 2), c.ball_speed)
self.ball = Ball(c.screen_width // 2,
c.screen_height // 2,
c.ball_radius,
c.ball_color,
speed)
self.objects.append(self.ball)
|
Вывод
В этой части мы рассмотрели обработку событий, таких как нажатия клавиш, движение мыши и щелчки мыши. Мы также погрузились в некоторые элементы игрового процесса Breakout, такие как перемещение весла, перемещение мяча и контроль скорости мяча.
Не забудьте также посмотреть, что у нас есть в наличии для продажи и для изучения на рынке Envato, если вы хотите изучить больше материалов, связанных с Python.
В четвертой части мы рассмотрим важную тему обнаружения столкновений и посмотрим, что происходит, когда мяч попадает в различные игровые объекты, такие как весло, кирпичи и даже стены, потолок и пол.
Тогда мы обратим наше внимание на игровое меню. Мы создадим пользовательские кнопки, которые будем использовать в качестве меню, которое мы можем показывать и скрывать по мере необходимости.