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

Структура небольшой игры: класс Game

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

До сих пор весь код жил в глобальных переменных и одном плоском цикле — нормально для учебного мини-проекта, но неудобно, как только игра обрастает состояниями (раздел 20.25), несколькими объектами и хоть какой-то паузой. Соберём всё, что вы узнали в этой главе, в один класс — тот самый архитектурный каркас, на котором построен финальный проект раздела 20.33 и космический шутер главы 21.

Gamescreenclockstaterunninghandle_events()update(dt)render()run()
Каждый метод отвечает ровно за одну фазу игрового цикла из раздела 20.14 — и не более того.

Это набросок каркаса, а не полный файл: он опускает импорт pygame , определение SHIRINA/VYSOTA, класс SostoyanieIgry из раздела 20.25 и тело метода toggle_pause() — всё это в реальном проекте, конечно, должно быть определено. Полный, действительно запускаемый пример такого класса — финальный проект раздела 20.33.

fragment_class_game.py
class Game:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((SHIRINA, VYSOTA))
        self.clock = pygame.time.Clock()
        self.state = SostoyanieIgry.MENU
        self.running = True

    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_p:
                self.toggle_pause()

    def update(self, dt):
        if self.state is not SostoyanieIgry.IGRA:
            return   # на паузе или в меню ничего не двигаем
        # здесь — обновление позиций, столкновений, счёта

    def render(self):
        self.screen.fill((20, 20, 40))
        # здесь — отрисовка всех объектов текущего состояния
        pygame.display.flip()

    def run(self):
        while self.running:
            dt = self.clock.tick(60) / 1000
            self.handle_events()
            self.update(dt)
            self.render()
        pygame.quit()

run() — единственное место, где виден весь цикл целиком, и он дословно повторяет три фазы из раздела 20.14: handle_events() это Input, update(dt) это Update, render() это Render. Именно так организован финальный bouncing_ball.py (раздел 20.33) — и в этом же стиле в главе 21 написан космический шутер.

Пауза не останавливает управление
Если проверку self.state is not SostoyanieIgry.IGRA поставить только в render(), а не в update(), экран во время паузы визуально замрёт правильно — но объекты продолжат двигаться в памяти, и после снятия паузы игра "телепортируется" туда, куда они успели дойти незаметно для игрока. Проверка состояния должна стоять именно в update(), а не только в отрисовке.
Практика: собираем класс Game
Pygame открывает нативное окно Python — выполните локально в VS Code, PyCharm или Jupyter
Практика выполняется локально
Открыть практику →