Глава 20 · Разработка игр с Pygame

Финальный проект: «Прыгающий мяч» с архитектурой Game

Тот же мяч, что и в разделе 20.5 — но теперь с архитектурой, которая переживёт рост проекта в нечто большее, чем один файл.

Вернёмся к прыгающему мячу из раздела 20.5 в последний раз — но теперь пересоберём его заново, применив всё, что глава добавила по пути: архитектуру класса Game (раздел 20.26), движение через delta time (раздел 20.16) и явные состояния игры (раздел 20.25).

myach : BouncingBallGamestate = SostoyanieIgry.IGRAx, y = 38.7, 328.8vx, vy = -182.5,…-122.9 # пикселей всекундуotskokov = 7schet = 70
Реальное состояние работающей игры в конкретный момент времени — то, что на самом деле хранится в памяти между кадрами. Обратите внимание на две закономерности: счёт всегда равен числу отскоков, умноженному на 10, а длина вектора скорости остаётся равной 220 пикселям в секунду — отскок разворачивает направление, но не меняет величину.

Что изменилось по сравнению с версией 20.5

bouncing_ball_basic.py (20.5)bouncing_ball.py (эта версия, Pro)
Организация кодаГлобальные переменные, плоские функцииКласс Game с методами handle_events/update/render/run
Движениеx += dx за кадр — зависит от FPSx += vx * dt — не зависит от FPS (раздел 20.16)
ПаузаНетЕсть, останавливает update(), не только отрисовку
РестартНет — нужно перезапускать программуКлавишей, без перезапуска процесса
СчётНетСчёт очков и счётчик отскоков
Взаимодействие мышьюНетКлик мышью — необязательный разворот мяча в сторону клика
bouncing_ball_pro_fragment.py
class BouncingBallGame:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((SHIRINA, VYSOTA))
        self.clock = pygame.time.Clock()
        self.state = SostoyanieIgry.IGRA
        self.running = True
        self._reset_myach()

    def update(self, dt):
        if self.state is not SostoyanieIgry.IGRA:
            return
        self.x += self.vx * dt
        self.y += self.vy * dt
        if self.x - RADIUS < 0 or self.x + RADIUS > SHIRINA:
            self.vx = -self.vx
            self.otskokov += 1
        if self.y - RADIUS < 0 or self.y + RADIUS > VYSOTA:
            self.vy = -self.vy
            self.otskokov += 1
Реальное окно: красный мяч у верхнего края тёмно-синего поля, вверху слева текст «Счёт: 10   Отскоков: 1»
Реальное окно: финальная Pro-версия во время игры — счёт и число отскоков растут вместе, как и должны по правилу из счёта очков: один отскок это десять очков.
Реальное окно: тот же мяч и счёт, поверх — жёлтая надпись «ПАУЗА — P, чтобы продолжить» по центру экрана
Реальное окно: состояние ПАУЗА — оверлей поверх замершего кадра, ровно то же положение мяча, что и до нажатия паузы.

Полный, уже проверенный файл — отдельно:

projects/pygame/bouncing-ball/bouncing_ball.py

★★ Самостоятельная задача
Столкновение мяча с мячом

Добавьте второй мяч и столкновение между двумя мячами через colliderect() (раздел 20.21), а не только со стенами.

★★★ Задача повышенной сложности
Меню и Game Over

Добавьте состояния MENU и GAME_OVER (раздел 20.25): игра стартует в MENU по нажатию клавиши, а после определённого числа отскоков переходит в GAME_OVER с финальным счётом на экране.

Практика: собираем финальную Pro-версию
Pygame открывает нативное окно Python — выполните локально в VS Code, PyCharm или Jupyter
Практика выполняется локально
Открыть практику →

Итоги главы

Что мы узнали в этой главе

  • Pygame — библиотека, а не движок: она даёт окно, отрисовку, ввод и звук, а структуру игры вы строите сами (раздел 20.8).
  • Разработка игр — целый мир ролей, жанров и платформ, и Pygame уверенно закрывает прежде всего десктоп, а веб и мобильные — через отдельные инструменты сообщества (разделы 20.6–20.13, 20.29–20.31).
  • В этой главе мы строили игровой цикл по базовой схеме Input → Update → Render, повторяемой десятки раз в секунду (раздел 20.14).
  • Движение в «пикселях за кадр» зависит от чужого железа; движение через delta time — нет (раздел 20.16).
  • pygame.Rect и colliderect() — основа столкновений, а хитбокс не обязан совпадать с рисунком (раздел 20.21).
  • Явные состояния игры (enum) и разделение handle_events(), update(dt), render() и run() — простая и удобная архитектура для небольших Pygame-проектов и хорошая основа для следующей главы (разделы 20.25–20.26).