Skip to content

Repository files navigation

🎮 Pygame Runner — учебный курс

Учебный курс по разработке 2D runner-игры на Pygame.

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

Курс показывает не только базовые возможности Pygame, но и постепенное развитие проекта: от одного простого файла до более аккуратной структуры с модулями, классами, менеджерами объектов, интерфейсом и отдельным состоянием игровой сессии.


Maintainability


📚 Содержание курса

# Лекция Тема
0 Подготовка окружения uv, Python 3.13, установка Pygame
1 Игровой цикл Окно, события, FPS, первая отрисовка
2 Изображения и ресурсы Surface, Rect, blit, папка assets
3 Анимация и runner-механика Анимация персонажа, движущийся фон, прыжок
4 Препятствия и монеты Столкновения, счёт, Game Over
5 Архитектура проекта Модули, классы, разделение ответственности
6 Меню и состояния игры menu, playing, pause, game_over
7 Звуки и музыка pygame.mixer, эффекты, фоновая музыка
8 Управляемый спавн SpawnManager, случайные промежутки между объектами
9 Менеджеры объектов BaseObjectManager, CoinManager, ObstacleManager
10 Интерфейс UIManager, меню, счёт, пауза, Game Over
11 Игровая сессия GameSession, счёт, лучший результат, скорость, состояние
12 Финальная сборка Чистка проекта, итоговая структура, проверка игры

🛠️ Стек

  • Python 3.13
  • uv — управление окружением и зависимостями
  • Pygame — библиотека для разработки 2D-игры
  • Ruff — линтер и форматтер
  • pre-commit — локальные проверки перед коммитом
  • GitHub Actions — CI-проверки на сервере

🚀 Быстрый старт

1. Клонировать репозиторий

git clone git@github.com:agkondakov91/PyGame.git
cd PyGame

2. Проверить uv

uv --version

Если uv не установлен:

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows PowerShell
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

3. Установить Python 3.13

uv python install 3.13

В проекте версия Python закреплена в файле .python-version:

3.13

4. Установить зависимости

uv sync --dev

Эта команда установит основные зависимости проекта и dev-инструменты.

5. Запустить игру

uv run python main.py

🎮 Управление

Действие Клавиши
Запустить игру из меню Enter или Space
Движение влево A или
Движение вправо D или
Прыжок W, или Space
Пауза P
Продолжить после паузы P
Рестарт после Game Over R
Возврат в меню после Game Over Esc

📂 Структура проекта

.
├── .github/
│   └── workflows/
│       └── lint.yml                  # CI-проверки через GitHub Actions
│
├── assets/
│   ├── images/
│   │   ├── background.png            # фон игры
│   │   ├── coin.png                  # монета
│   │   ├── obstacle.png              # препятствие
│   │   ├── player_right_1.png        # кадры анимации игрока
│   │   ├── player_right_2.png
│   │   ├── player_right_3.png
│   │   └── player_right_4.png
│   │
│   └── sounds/
│       ├── coin.wav                  # звук сбора монеты
│       ├── hit.wav                   # звук столкновения
│       ├── jump.wav                  # звук прыжка
│       └── music.mp3                 # фоновая музыка
│
├── src/
│   └── runner/
│       ├── __init__.py
│       ├── assets.py                 # пути и загрузка ресурсов
│       ├── background.py             # движущийся фон
│       ├── coin.py                   # объект монеты
│       ├── constants.py              # константы проекта
│       ├── game.py                   # главный координатор игры
│       ├── obstacle.py               # объект препятствия
│       ├── player.py                 # игрок, движение, прыжок, анимация
│       ├── session.py                # состояние игровой сессии
│       ├── sound.py                  # звуки и музыка
│       ├── spawn.py                  # управление появлением объектов
│       ├── ui.py                     # интерфейс игры
│       │
│       └── managers/
│           ├── __init__.py
│           ├── base_manager.py       # базовый менеджер игровых объектов
│           ├── coin_manager.py       # менеджер монет
│           └── obstacle_manager.py   # менеджер препятствий
│
├── .gitignore
├── .pre-commit-config.yaml           # настройки pre-commit
├── .python-version                   # закреплённая версия Python
├── main.py                           # точка входа
├── pyproject.toml                    # настройки проекта и зависимостей
├── uv.lock                           # lock-файл зависимостей
└── README.md

🧩 Архитектура проекта

Проект постепенно развивается от простого игрового цикла к более аккуратной архитектуре.

main.py

Точка входа в приложение.

from src.runner.game import Game


def main() -> None:
    game = Game()
    game.run()


if __name__ == "__main__":
    main()

main.py не содержит игровой логики. Он только создаёт объект игры и запускает главный цикл.


Game

Главный координатор игры.

Класс Game отвечает за:

  • инициализацию Pygame;
  • создание окна;
  • главный игровой цикл;
  • обработку событий;
  • вызов обновления объектов;
  • проверку столкновений;
  • вызов отрисовки;
  • завершение игры.

Game не должен вручную управлять каждой монетой, каждым препятствием, каждым текстом интерфейса и каждой настройкой состояния. Для этого есть отдельные классы.


GameSession

Класс GameSession хранит данные текущей игровой сессии:

  • текущее состояние игры;
  • текущий счёт;
  • лучший результат;
  • множитель скорости.

Он отвечает за действия:

self.session.start_game()
self.session.pause()
self.session.resume()
self.session.finish_game()
self.session.go_to_menu()
self.session.add_score(points)
self.session.increase_speed()

Это делает код выразительнее: вместо прямого изменения строк и чисел используются методы, отражающие смысл игровых действий.


UIManager

Класс UIManager отвечает за отрисовку интерфейса:

  • стартовое меню;
  • текущий счёт;
  • лучший результат;
  • множитель скорости;
  • экран паузы;
  • экран Game Over.

Благодаря этому Game не хранит шрифты и не содержит координаты каждого текста.


BaseObjectManager

Базовый менеджер игровых объектов.

Он содержит общее поведение для групп объектов:

  • создать несколько объектов;
  • сбросить их позиции;
  • обновить все объекты;
  • пересоздать объект, если он вышел за экран;
  • нарисовать все объекты.

От него наследуются:

CoinManager
ObstacleManager

CoinManager

Менеджер монет.

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

При сборе монеты счёт увеличивается, а монета появляется снова дальше по уровню.


ObstacleManager

Менеджер препятствий.

Он управляет списком препятствий, обновляет их, рисует и проверяет столкновение игрока с препятствием.

При столкновении игра переходит в состояние Game Over.


SpawnManager

Класс, который отвечает за появление объектов справа от экрана.

Он выдаёт следующую координату по оси x с учётом случайного промежутка.

Для препятствий и монет используются разные диапазоны:

OBSTACLE_SPAWN_MIN_GAP = 450
OBSTACLE_SPAWN_MAX_GAP = 750

COIN_SPAWN_MIN_GAP = 250
COIN_SPAWN_MAX_GAP = 500

Это позволяет делать препятствия более редкими, а монеты — более частыми.


🔁 Игровой цикл

Основа Pygame-игры — игровой цикл:

while self.running:
    self.handle_events()

    if self.session.is_playing():
        self.update()

    self.draw()

    pygame.display.update()
    self.clock.tick(FPS)

Каждый кадр игра:

  1. обрабатывает события;
  2. обновляет игровой мир;
  3. рисует новый кадр;
  4. обновляет экран;
  5. ограничивает FPS.

Если игра находится в меню, на паузе или на экране Game Over, игровой мир не обновляется.


🧠 Состояния игры

В проекте используются состояния:

STATE_MENU = "menu"
STATE_PLAYING = "playing"
STATE_PAUSE = "pause"
STATE_GAME_OVER = "game_over"

Схема переходов:

menu
  ↓ Enter / Space

playing
  ↓ P
pause
  ↓ P
playing

playing
  ↓ столкновение с препятствием
game_over

game_over
  ↓ R
playing

game_over
  ↓ Esc
menu

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


💥 Столкновения и хитбоксы

Pygame позволяет проверять столкновения через Rect:

player_hitbox.colliderect(obstacle_hitbox)

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

PLAYER_HITBOX_INFLATE = (-40, -30)
OBSTACLE_HITBOX_INFLATE = (-30, -40)
COIN_HITBOX_INFLATE = (-15, -15)

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


🔧 Полезные команды

Запустить игру

uv run python main.py

Проверить версию Python

uv run python --version

Установить зависимости

uv sync --dev

Посмотреть установленные пакеты

uv pip list

Запустить Ruff

uv run ruff check .

Исправить часть ошибок Ruff автоматически

uv run ruff check --fix .

Проверить форматирование

uv run ruff format --check .

Отформатировать проект

uv run ruff format .

Установить pre-commit hooks

uv run pre-commit install

Запустить pre-commit вручную

uv run pre-commit run --all-files

⚙️ Конфигурация

Основные настройки проекта находятся в pyproject.toml.

Пример:

[project]
name = "pygame_test"
version = "0.1.0"
description = "Educational Pygame runner project"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "pygame>=2.6.1",
]

[dependency-groups]
dev = [
    "pre-commit>=4.6.0",
    "ruff>=0.15.17",
]

[tool.ruff]
line-length = 88

[tool.ruff.lint]
select = ["E", "W", "F", "N", "I"]
ignore = ["E501"]

[tool.ruff.format]
quote-style = "single"

✅ Проверка перед завершением проекта

Перед тем как считать проект готовым, нужно пройтись по чек-листу:

1. Игра запускается через uv run python main.py.
2. При запуске появляется меню.
3. Enter или Space запускает игру.
4. Игрок анимируется.
5. Фон движется.
6. Игрок двигается влево и вправо.
7. Игрок прыгает.
8. Монеты появляются.
9. Монеты собираются.
10. Score увеличивается.
11. Препятствия появляются.
12. Столкновение с препятствием переводит игру в Game Over.
13. На экране Game Over отображается Final score.
14. Best score обновляется.
15. R запускает новую попытку.
16. Esc возвращает в меню.
17. P включает паузу.
18. Повторное P снимает паузу.
19. Музыка играет.
20. Звук прыжка работает.
21. Звук монеты работает.
22. Звук столкновения работает.

🐞 Частые проблемы

ModuleNotFoundError: No module named 'pygame'

Скорее всего, проект запускается не через uv.

Правильно:

uv run python main.py

Неправильно:

python main.py

Картинка не загружается

Проверь:

  • файл лежит в assets/images/;
  • имя файла совпадает с тем, что указано в коде;
  • расширение файла совпадает: .png, .jpg, .jpeg;
  • проект запускается из корня репозитория.

Звук не воспроизводится

Проверь:

  • файл лежит в assets/sounds/;
  • имя файла совпадает с кодом;
  • окно Pygame активно;
  • звук не выключен в системе;
  • формат файла поддерживается.

Столкновение происходит слишком рано

Проблема обычно в том, что исходный Rect изображения больше видимой части объекта.

Решение — использовать уменьшенный хитбокс:

player_hitbox = player.rect.inflate(*PLAYER_HITBOX_INFLATE)

Монеты или препятствия появляются слишком редко

Проверь значения в constants.py:

OBSTACLE_SPAWN_MIN_GAP = 450
OBSTACLE_SPAWN_MAX_GAP = 750

COIN_SPAWN_MIN_GAP = 250
COIN_SPAWN_MAX_GAP = 500

Если объекты появляются слишком редко, диапазоны можно уменьшить.

Если появляются слишком часто, диапазоны можно увеличить.


📖 Полезные ссылки


💡 Идеи для самостоятельного развития

После завершения курса проект можно развивать дальше:

сохранять best_score в файл;
добавить анимацию монеты;
добавить разные типы препятствий;
добавить разные уровни сложности;
добавить здоровье игрока;
добавить бонусы;
добавить выбор персонажа;
добавить экран настроек;
добавить кнопку выключения музыки;
добавить параллакс-фон;
добавить стартовый обратный отсчёт;
добавить таблицу рекордов;
собрать игру в исполняемый файл.

👨‍🏫 Об авторе

Курс подготовлен для студентов, изучающих Python-разработку и основы создания 2D-игр.

Преподаватель: Александр / agkondakov91

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages