Гид по технологиям

Меню запуска и экран «Игра окончена» в PyGame

4 min read Разработка игр Обновлено 02 Jan 2026
Старт и экран «Игра окончена» в PyGame
Старт и экран «Игра окончена» в PyGame

В этой статье показано, как добавить стартовое меню и экран «Игра окончена» в простую игру на PyGame. Приведён исправленный и расширенный пример кода с управлением состояниями, обработкой ввода клавиатуры, перезапуском и базовыми советами по UI и тестированию.

игра со стартовым экраном и экраном «Игра окончена»

Зачем разделять состояния игры

Разделение логики игры на состояния (start, game, game_over) упрощает код, делает поведение предсказуемым и облегчает ввод новых экранов: настроек, паузы, таблицы рекордов. Это базовый паттерн для большинства 2D-игр.

Краткое определение терминов

  • Состояние игры: текущий экран или режим работы (например, стартовое меню, игровой процесс, экран конца игры).
  • Рендер: отрисовка объектов на экране.

Создание простой игры — минимальная версия

Перед добавлением меню полезно иметь простейшую игру для проверки взаимодействия. Ниже сниппет, адаптированный под Python/PyGame, с минимальной логикой: игрок-куб, препятствие-куб, детекция столкновений.

import pygame

pygame.init()

screen_width = 750
screen_height = 450
screen = pygame.display.set_mode((screen_width, screen_height))

obstacle_x = 400
obstacle_y = 400
obstacle_w = 40
obstacle_h = 40
player_x = 200
player_y = 400
player_w = 20
player_h = 20

clock = pygame.time.Clock()

running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player_x -= 5
    if keys[pygame.K_RIGHT]:
        player_x += 5

    # Коллизия
    if (player_x + player_w > obstacle_x and player_x < obstacle_x + obstacle_w
            and player_y + player_h > obstacle_y and player_y < obstacle_y + obstacle_h):
        # В этой упрощённой версии можно просто выйти или обработать состояние
        running = False

    screen.fill((0, 0, 0))
    pygame.draw.rect(screen, (255, 0, 0), (obstacle_x, obstacle_y, obstacle_w, obstacle_h))
    pygame.draw.rect(screen, (0, 255, 0), (player_x, player_y, player_w, player_h))
    pygame.display.update()
    clock.tick(60)

pygame.quit()

простой пример игры на Pygame (квадраты)

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

Стартовое меню — что отображать

Стартовое меню должно быть простым и информативным: название игры, краткая инструкция по управлению, кнопка “Старт” или подсказка клавиши. Важно обеспечить явный фокус: что нажать для начала.

Пример функции отрисовки стартового меню (строки локализованы на русский):

def draw_start_menu(screen, screen_w, screen_h, font):
    screen.fill((0, 0, 0))
    title = font.render('Моя игра', True, (255, 255, 255))
    hint = font.render('Пробел — начать', True, (200, 200, 200))
    screen.blit(title, (screen_w/2 - title.get_width()/2, screen_h/2 - title.get_height()))
    screen.blit(hint, (screen_w/2 - hint.get_width()/2, screen_h/2 + 10))
    pygame.display.update()

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

простой Pygame — стартовый экран

Экран «Игра окончена» — что добавить

Экран конца игры обычно показывает причину завершения, очки и варианты: перезапустить либо выйти. Важно дать пользователю очевидный путь дальше.

Пример функции экрана конца игры:

def draw_game_over(screen, screen_w, screen_h, font, score=None):
    screen.fill((0, 0, 0))
    title = font.render('Игра окончена', True, (255, 255, 255))
    restart = font.render('R — перезапуск', True, (200, 200, 200))
    quit_text = font.render('Q — выход', True, (200, 200, 200))
    screen.blit(title, (screen_w/2 - title.get_width()/2, screen_h/2 - title.get_height()))
    if score is not None:
        score_text = font.render(f'Очки: {score}', True, (255, 255, 0))
        screen.blit(score_text, (screen_w/2 - score_text.get_width()/2, screen_h/2))
    screen.blit(restart, (screen_w/2 - restart.get_width()/2, screen_h/2 + 40))
    screen.blit(quit_text, (screen_w/2 - quit_text.get_width()/2, screen_h/2 + 80))
    pygame.display.update()

простая игра Pygame — экран «Игра окончена»

Полный улучшенный пример: состояние, сброс, защита от ошибок

Ниже полный рабочий пример с исправлениями: введён флаг running, корректная инициализация game_over, таймер кадра, функция сброса состояния, аккуратная обработка клавиш и явная установка состояний.

import pygame

pygame.init()

screen_w = 750
screen_h = 450
screen = pygame.display.set_mode((screen_w, screen_h))
font = pygame.font.SysFont('arial', 36)
clock = pygame.time.Clock()

# Игровые параметры
obstacle = {'x': 400, 'y': 400, 'w': 40, 'h': 40}
player = {'x': 200, 'y': 400, 'w': 20, 'h': 20}

# Состояния: 'start', 'game', 'game_over'
game_state = 'start'
score = 0
running = True


def reset_game():
    player['x'] = 200
    player['y'] = 400
    # При необходимости: менять положение препятствия, очки и т.д.
    global score
    score = 0


def draw_start():
    draw_start_menu(screen, screen_w, screen_h, font)


def draw_start_menu(screen, screen_w, screen_h, font):
    screen.fill((10, 10, 30))
    title = font.render('Моя игра', True, (255, 255, 255))
    hint = font.render('Пробел — начать', True, (200, 200, 200))
    screen.blit(title, (screen_w/2 - title.get_width()/2, screen_h/2 - 60))
    screen.blit(hint, (screen_w/2 - hint.get_width()/2, screen_h/2))
    pygame.display.update()


def draw_game():
    screen.fill((0, 0, 0))
    pygame.draw.rect(screen, (255, 0, 0), (obstacle['x'], obstacle['y'], obstacle['w'], obstacle['h']))
    pygame.draw.rect(screen, (0, 255, 0), (player['x'], player['y'], player['w'], player['h']))
    # Простейший счет
    score_text = font.render(f'Очки: {score}', True, (255, 255, 255))
    screen.blit(score_text, (10, 10))
    pygame.display.update()


def draw_game_over_screen():
    draw_game_over(screen, screen_w, screen_h, font, score)


def draw_game_over(screen, screen_w, screen_h, font, score=None):
    screen.fill((30, 0, 0))
    title = font.render('Игра окончена', True, (255, 255, 255))
    restart = font.render('R — перезапуск', True, (200, 200, 200))
    quit_text = font.render('Q — выход', True, (200, 200, 200))
    screen.blit(title, (screen_w/2 - title.get_width()/2, screen_h/2 - 60))
    if score is not None:
        score_text = font.render(f'Очки: {score}', True, (255, 255, 0))
        screen.blit(score_text, (screen_w/2 - score_text.get_width()/2, screen_h/2 - 10))
    screen.blit(restart, (screen_w/2 - restart.get_width()/2, screen_h/2 + 30))
    screen.blit(quit_text, (screen_w/2 - quit_text.get_width()/2, screen_h/2 + 70))
    pygame.display.update()

# Инициалный сброс
reset_game()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()

    if game_state == 'start':
        draw_start()
        if keys[pygame.K_SPACE]:
            reset_game()
            game_state = 'game'

    elif game_state == 'game':
        # Управление игроком
        if keys[pygame.K_LEFT]:
            player['x'] -= 5
        if keys[pygame.K_RIGHT]:
            player['x'] += 5

        # Простейшая логика роста очков со временем
        score += 1

        # Проверка столкновения
        if (player['x'] + player['w'] > obstacle['x'] and player['x'] < obstacle['x'] + obstacle['w']
                and player['y'] + player['h'] > obstacle['y'] and player['y'] < obstacle['y'] + obstacle['h']):
            game_state = 'game_over'

        draw_game()

    elif game_state == 'game_over':
        draw_game_over_screen()
        if keys[pygame.K_r]:
            game_state = 'start'
        if keys[pygame.K_q]:
            running = False

    clock.tick(60)

pygame.quit()

Этот вариант устраняет несколько общих ошибок: неопределённые флаги, некорректные ветвления в цикле, отсутствие лимита FPS, отсутствие функции сброса состояния.

Советы по улучшению UI и взаимодействия

  • Шрифт и читаемость: выбирайте моно/без засечек шрифты с хорошим размером для основного текста.
  • Обратная связь: небольшая анимация, звук или вспышка при столкновении усиливают впечатление.
  • Доступность: поддержка клавиатуры и мыши, понятные подсказки.
  • Кликабельные кнопки: сделайте область кнопки и обработку mousebutton для удобства на тач/мыши.

Важно: тестируйте UI на разных разрешениях и соотношениях сторон.

Варианты и когда предложенный подход не подходит

  • Когда это крупный проект: для больших игр лучше использовать архитектуру “сцен” или готовый фреймворк (например, Godot) с системой сцен и сигналов.
  • Для сложной логики и анимаций: переходите к объектно-ориентированному подходу, ECS или сторонним менеджерам состояний.

Полезные альтернативы и паттерны

  • Scene manager: отдельный класс, который переключает сцены и хранит стек экранов.
  • FSM (Finite State Machine): явная машина состояний для управления переходами.
  • Компонентный подход: объекты с компонентами для рендеринга, физики и ввода.

Ментальные модели и heuristics

  • Один экран — одна функция/класс: упрощает тестирование.
  • Явные переходы состояний: избегайте скрытых побочных эффектов при смене состояния.
  • Инициализация до запуска: заранее подготовьте ресурсы (шрифты, звуки), чтобы избежать лагов.

Мини-процесс разработки

  1. Реализовать минимальную игровую петлю и базовую механику.
  2. Добавить устройство состояний (start, game, game_over).
  3. Сделать функции отрисовки для каждого состояния.
  4. Обработать ввод клавиатуры и мыши.
  5. Добавить сброс состояния и проверку граничных условий.
  6. Протестировать и собрать отзывы.

Критерии приёмки

  • При старте приложения показывается стартовое меню.
  • При нажатии пробела игра начинается и управляется стрелками влево/вправо.
  • При столкновении появляется экран «Игра окончена» с подсказками R и Q.
  • Клавиша R возвращает в стартовое меню, Q корректно завершает приложение.
  • FPS стабилен (например, ~60) и нет утечек событий.

Набор тестов и приемочные сценарии

  • Нажать пробел на стартовом экране: ожидается переход в игровой режим.
  • Во время игры нажать стрелки: игрок должен сдвигаться по X.
  • Создать искусственную коллизию: ожидается переход в game_over.
  • На экране конца игры нажать R: возвращаемся в старт.
  • На экране конца игры нажать Q: приложение закрывается.

Быстрый чек-лист для релиза

  • Шрифты и текст читаемы на целевом разрешении
  • Кнопки интерактивны клавиатурой и мышью
  • Есть обработка закрытия окна
  • Таймер кадров установлен
  • Имеется функция сброса состояния

Примеры расширений (идеи для следующего шага)

  • Добавить меню опций (звук, управление).
  • Сделать кнопку мышью и анимацию наведения.
  • Добавить таблицу рекордов с локальным сохранением.

Короткое резюме

Разделение игры на понятные состояния упрощает разработку и тестирование. В статье представлен рабочий и улучшенный шаблон с стартовым меню, игровым процессом и экраном «Игра окончена», а также рекомендации по UI, тестам и дальнейшему развитию.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Включить гибернацию в Windows 11 — инструкция
Windows

Включить гибернацию в Windows 11 — инструкция

Следите за ЧМ-2022 через Google на Android
Спорт

Следите за ЧМ-2022 через Google на Android

Что ждать от презентации Google: Pixel 8 и Pixel Watch 2
Гаджеты

Что ждать от презентации Google: Pixel 8 и Pixel Watch 2

Переименование фото по дате съёмки — Namexif и Stamp
Фото

Переименование фото по дате съёмки — Namexif и Stamp

Шифрование и защита смартфона: простые шаги
Безопасность

Шифрование и защита смартфона: простые шаги

Как создать и удалить группу в LinkedIn
SMM

Как создать и удалить группу в LinkedIn