Перейти к основному содержимому

Разработка игр на Python

Разработчику Архитектору

Разработка игр на Python

Основы разработки игр на Python

Python не является основным языком в индустрии разработки игр. Его динамическая типизация, интерпретируемая природа и относительно низкая производительность делают его малопригодным для создания ресурсоёмких проектов — таких как AAA-игры или масштабные многопользовательские онлайн-платформы. Однако Python остаётся мощным инструментом в контексте обучения, прототипирования, скриптования игровой логики и реализации простых 2D-приложений.

Для этих целей существует ряд библиотек, позволяющих организовать графический вывод, обработку ввода, аудиосопровождение и базовую физику. Наиболее известной и долгоживущей из них является Pygame — кроссплатформенная библиотека, построенная на основе SDL (Simple DirectMedia Layer). Она предоставляет минимально необходимый набор средств для создания 2D-игр и используется преимущественно в образовательных целях, а также в инди-проектах небольшого масштаба.

Python не предназначен для создания игровых движков уровня Unreal Engine или Unity. Тем не менее, он может эффективно применяться как средство обучения основам геймдева, анализа алгоритмов поведения персонажей, реализации ИИ в играх, а также как платформа для быстрого прототипирования механик.

Что касается других технологий, то Godot поддерживает язык GDScript, синтаксически близкий к Python, но это не Python. Начиная с версии 4.0, Godot также предлагает официальную поддержку Python через модуль GDExtension (на базе Cython), однако использование Python в Godot — скорее исключение, чем правило. Основная экосистема Godot ориентирована на GDScript, C# и C++. Таким образом, утверждение о том, что Godot "использует Python" — упрощение, не соответствующее действительности в полной мере.

В рамках данной главы мы сосредоточимся на Pygame — наиболее доступной и документированной библиотеке для разработки 2D-игр на чистом Python. Короткие готовые скрипты (змейка, Pong, Breakout и др.) с построчным разбором — в Pygame — мини-игры на Python. Пошаговые крупные проекты (Tetris, Match3, аркады и др.) собраны в Практикуме разработки игр.

Если цель — мобильная игра с сенсорным управлением на том же Python, см. Kivy — мобильные приложения и игры на Python и Практикум Kivy (2048, Pong, Snake).

Если ученик учит Python через Minecraft Java (внешние скрипты mcpi, RaspberryJuice), сначала полезны встроенные команды и datapack, затем Разработка в Minecraft.

Для трёхмерной графики (камера, освещение, 3D-модели) см. отдельную главу Трёхмерная графика и Panda3D — движок Panda3D с примерами карточки, текстуры и куба. Если нужен редактор движка и C# вместо Python — Разработка на Unity и готовые MonoBehaviour в Lab.

Для окон с формами и кнопками без игровой логики — Tkinter — окна и виджеты (теория GUI).

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

Библиотека не является игровым движком в строгом смысле слова. У неё отсутствуют встроенные системы анимаций, физики, сцен, шейдеров или редактор ресурсов. Вместо этого Pygame предоставляет низкоуровневые примитивы, которые разработчик должен компоновать самостоятельно, реализуя игровую логику "с нуля".

Тем не менее, именно эта особенность делает Pygame ценным инструментом для обучения: он заставляет разработчика понимать внутренние механизмы работы игрового цикла, обработки событий и управления состоянием объектов.


Консольные игры

Перед графикой и Pygame полезно собрать несколько текстовых игр в терминале. Они тренируют те же навыки — цикл, условия, случайные числа, хранение состояния. Любая такая игра строится по схеме ввод → обновление состояния → вывод.

Минимальный "игровой цикл" без графики:

while True:
cmd = input("команда (стоп): ")
if cmd == "стоп":
break
print("Выполнено:", cmd)

Разбор фрагмента:

  • while True задаёт бесконечный цикл игры/приложения.
  • input(...) получает действие пользователя, а if ... break — условие завершения цикла.
  • Это минимальный шаблон game loop: ввод -> проверка условия -> реакция.

Угадай число — классический первый проект с random и while:


import random

secret = random.randint(1, 10)
while True:
guess = int(input("Число от 1 до 10: "))
if guess == secret:
print("Угадал!")
break
print("Ещё раз!")

Камень, ножницы, бумага — сравнение ввода пользователя со случайным выбором:


import random

choices = ["камень", "ножницы", "бумага"]
player = input("Твой ход: ")
bot = random.choice(choices)
print("Компьютер:", bot)
if player == bot:
print("Ничья")
elif (player, bot) in [("камень", "ножницы"), ("ножницы", "бумага"), ("бумага", "камень")]:
print("Ты победил!")
else:
print("Компьютер победил")

Виселица (упрощённо) — строка, множество угаданных букв и счётчик попыток:

Код ITЗагрузка примера кода…

Когда логика в консоли работает, тот же цикл "состояние + ввод + обновление" переносится в Pygame — меняется только способ вывода (окно вместо print). Готовые мини-игры с разбором строк — в Pygame — мини-игры на Python — змейка, Pong, Breakout, тест реакции и др.


Pygame

Pygame представляет собой набор модулей Python, предоставляющий доступ к низкоуровневым функциям мультимедиа через привязки к библиотеке SDL (Simple DirectMedia Layer). Библиотека обеспечивает работу с графикой, звуком, вводом с клавиатуры, мыши и геймпадов. Система включает средства обработки времени и обнаружения столкновений.

Библиотека строится на основе SDL, написанной на языке C. Python-код выступает обёрткой, передающей команды в низкоуровневую среду. Это определяет производительность и кроссплатформенность. Поддерживаются операционные системы Windows, macOS, Linux.

Установка выполняется через менеджер пакетов pip:

pip install pygame

Проверка установки возможна через вывод версии модуля:


import pygame

print(pygame.ver)

Разбор фрагмента:

  • Импорт pygame проверяет доступность библиотеки в окружении.
  • pygame.ver выводит версию установленного пакета и помогает быстро диагностировать несовместимости.

Любое приложение на Pygame содержит базовый набор вызовов. Отсутствие любого из них приводит к ошибке выполнения или некорректной работе графического интерфейса.

  1. Импорт модуля: import pygame.
  2. Инициализация: pygame.init(). Запускает внутренние подсистемы (видео, аудио, ввод).
  3. Создание окна: pygame.display.set_mode(). Возвращает объект поверхности экрана.
  4. Игровой цикл: Бесконечный цикл while, обрабатывающий события и обновляющий кадр.
  5. Завершение: pygame.quit() и выход из интерпретатора.

Пример минимальной структуры:

Код ITЗагрузка примера кода…

Разбор фрагмента:

  • pygame.init() инициализирует подсистемы (видео, ввод, звук).
  • В цикле pygame.event.get() обрабатываются события окна, включая QUIT.
  • screen.fill(...) очищает кадр перед отрисовкой, а display.flip() выводит готовый кадр на экран.
  • pygame.quit() освобождает ресурсы SDL при завершении.

Тот же каркас с комментариями к каждой строке и таблицей типичных ошибок — в Lab: мини-игры на Pygame.

Библиотека разделена на логические модули. Каждый модуль отвечает за конкретную задачу.

МодульНазначениеКлючевые объекты
pygame.displayУправление окном и экраномSurface, set_mode, flip, update
pygame.drawРисование примитивовcircle, rect, line, polygon
pygame.fontРабота со шрифтами и текстомFont, render, SysFont
pygame.eventОбработка событий вводаget, poll, QUIT, KEYDOWN
pygame.timeКонтроль времени и кадровClock, tick, get_ticks
pygame.imageЗагрузка и сохранение изображенийload, save, fromstring
pygame.mixerВоспроизведение звукаSound, music, play, stop
pygame.spriteУправление игровыми объектамиSprite, Group, spritecollideсправочник
pygame.rectПрямоугольники и коллизииRect, colliderect, move
pygame.keyСостояние клавиатурыget_pressed, name
pygame.mouseСостояние мышиget_pos, get_pressed, set_visible

Вызов pygame.init() активирует все доступные модули. Существует возможность инициализации отдельных подсистем для экономии ресурсов, например pygame.display.init() или pygame.mixer.init(). Функция pygame.get_init() возвращает статус инициализации. Функция pygame.quit() выключает все модули.


Простое управление спрайтом

Чтобы реализовать простейшее управление через W, A, S, D, в Pygame необходимо выполнить следующие шаги:

  1. Создать класс, наследуемый от pygame.sprite.Sprite.
  2. Инициализировать изображение (или цветной прямоугольник для прототипа) и задать его позицию (rect).
  3. Обработать события клавиатуры (KEYDOWN и KEYUP) для отслеживания нажатия и отпускания клавиш.
  4. В методе обновления (update) изменять координаты спрайта в зависимости от текущего состояния клавиш.
  5. Добавить проверку границ экрана, чтобы спрайт не уходил за пределы видимой области.

Ниже приведен полный, рабочий пример кода. Сохраните его в файл main.py и запустите из терминала:

pip install pygame
python main.py

Закрыть окно — крестик или Alt+F4. Если используете картинки (pygame.image.load), файлы должны лежать в той же папке, что и скрипт.

Код ITЗагрузка примера кода…

Ключевые моменты реализации:

  1. Состояние клавиш: Вместо прямого изменения координат внутри обработчика событий используется словарь keys_pressed. Это позволяет реализовать плавное движение при одновременном нажатии нескольких клавиш (например, диагональ W+A). Если менять координаты только в событии KEYDOWN, движение будет рывками.
  2. Границы экрана: В методе update добавлены проверки (self.rect.top > 0 и т.д.), чтобы спрайт не выходил за пределы игрового поля.
  3. Оптимизация: Использование pygame.sprite.Group упрощает управление несколькими объектами, если в будущем потребуется добавить врагов или препятствия.
  4. Объективность: Код использует стандартные возможности Pygame без сторонних библиотек, что гарантирует совместимость и предсказуемость поведения.

Если вам потребуются более сложные механики (столкновения, анимация, использование изображений .png вместо цветных квадратов), это можно реализовать путем загрузки изображения через pygame.image.load() и добавления методов обработки коллизий.

В Lab уже разобраны спрайты, Group и spritecollide на примере шутера — вид сверху — стрельба. Змейка и Pong там же: змейка, Pong.


Пошаговое расширение — враг, столкновения, снаряды

Тот же каркас — события → update() → отрисовка — масштабируется по шагам. Каждый новый объект — отдельный класс-спрайт и своя Group.

Шаг 1. Враг. Класс наследует pygame.sprite.Sprite, движение только в update():

class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((30, 30))
self.image.fill((0, 255, 0))
self.rect = self.image.get_rect(center=(400, 100))
self.speed_x = 3
self.direction = 1 # 1 — вправо, -1 — влево

def update(self):
self.rect.x += self.speed_x * self.direction
if self.rect.right >= SCREEN_WIDTH or self.rect.left <= 0:
self.direction *= -1

Второй противник — преследование игрока. Тот же каркас спрайта, но в update() враг сравнивает свои координаты с player и сдвигается к нему по осям. Ссылку на игрока передаём в конструктор:

Код ITЗагрузка примера кода…

По диагонали такой враг движется быстрее, чем по одной оси; для равной скорости в любом направлении нормализуйте вектор к игроку (см. раздел "Спрайт противника и движение" ниже).

В main() добавьте enemies = pygame.sprite.Group(), создайте обоих врагов и включите их в all_sprites и enemies:

enemies = pygame.sprite.Group()
patrol = Enemy()
chaser = ChasingEnemy(player)
all_sprites.add(patrol, chaser)
enemies.add(patrol, chaser)

Шаг 2. Столкновение врага с игроком. После all_sprites.update():

hits = pygame.sprite.spritecollide(player, enemies, False)
if hits:
running = False # или урон, отбрасывание, мигание

Третий аргумент dokill: False — враг остаётся; True — спрайт удаляется из всех групп при касании.

Шаг 3. Снаряды и попадания. Отдельная группа bullets. Снаряд двигается в update() и исчезает за краем экрана:

Код ITЗагрузка примера кода…

Выстрел по клику мыши (направление от игрока к курсору):

elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
mx, my = event.pos
dx = mx - player.rect.centerx
dy = my - player.rect.centery
length = (dx ** 2 + dy ** 2) ** 0.5
if length > 0:
dx /= length
dy /= length
bullet = Bullet(player.rect.centerx, player.rect.centery, dx, dy)
all_sprites.add(bullet)
bullets.add(bullet)

Попадание по врагам (True уничтожает врага при попадании):

for bullet in bullets:
hits = pygame.sprite.spritecollide(bullet, enemies, True)
if hits:
bullet.kill()

Стрельба по клавише SPACE с фиксированным направлением (например, вверх — dir_x=0, dir_y=-1) — проще, но менее гибко, чем прицеливание мышью.

Кулдаун. Событие MOUSEBUTTONDOWN срабатывает один раз за клик; для ограничения частоты огня храните время последнего выстрела через pygame.time.get_ticks() и сравнивайте с задержкой в миллисекундах.

Итог по группам из пошагового расширения:

  • all_sprites — все объекты, которые нужно обновлять и рисовать каждый кадр
  • enemies — только враги, для проверки касания с игроком или пулями
  • bullets — только снаряды, для groupcollide с enemies

Дальше — как устроен модуль pygame.sprite целиком. Специализированные классы (DirtySprite, RenderUpdates и др.) собраны в справочнике по pygame.sprite.


Модуль pygame.sprite — архитектура объектов

Спрайт в Pygame — любой видимый игровой объект: игрок, враг, пуля, монетка, кнопка меню. Модуль pygame.sprite помогает хранить такие объекты в группах, рисовать их одной командой и проверять столкновения.

Две опорные сущности:

  • pygame.sprite.Sprite — шаблон одного объекта (картинка + позиция + логика кадра)
  • pygame.sprite.Group — контейнер со спрайтами; умеет вызывать update() и draw() сразу для всех членов

Термины, которые встретятся дальше:

  • Surface (поверхность) — картинка в памяти, набор пикселей; у спрайта лежит в self.image
  • Rect (прямоугольник) — координаты и размер на экране; у спрайта лежит в self.rect; по нему чаще всего считают столкновения
  • Коллизия (столкновение) — два объекта пересеклись на экране; игра реагирует (урон, сбор предмета, уничтожение пули)
  • Хитбокс — зона, по которой проверяют касание; в Pygame это обычно rect, даже если картинка сложной формы

Перед чтением полезно пройти простое управление спрайтом и пошаговое расширение с врагами и пулями. Там те же идеи на рабочем коде.

Что должен уметь класс-спрайт

pygame.sprite.Sprite сам по себе ничего не рисует. Вы создаёте наследника (class Player(pygame.sprite.Sprite)) и задаёте три вещи:

ЧтоГде в кодеРоль
Картинкаself.image (pygame.Surface)Что увидит игрок. Файл через pygame.image.load(), для прототипа — цветной Surface
Позиция и размерself.rect (pygame.Rect)Где объект на экране. Часто self.rect = self.image.get_rect() и сдвиг center / topleft
Логика кадраupdate(self, ...)Движение, таймеры, анимация. Group.update() вызовет этот метод у каждого спрайта в группе

Минимальный каркас:

Код ITЗагрузка примера кода…

В __init__ обязателен вызов super().__init__(). Он регистрирует спрайт во внутренних структурах Pygame; без него add() в группу может не сработать. Про наследование классов — ООП в Python.

Жизненный цикл (add, remove, kill, alive)

Спрайт попадает в игру через группу и исчезает из неё же.

МетодЧто делает
sprite.add(group, ...)Добавляет спрайт в одну или несколько групп
sprite.remove(group, ...)Убирает только из перечисленных групп
sprite.kill()Убирает из всех групп сразу; стандартный способ убрать пулю или врага
sprite.alive()Возвращает True, пока спрайт хотя бы в одной группе

Параметр dokill у spritecollide и groupcollide делает то же, что ручной kill(), но автоматически для всех объектов из списка столкновений. Пример из пошагового расширения:

  • spritecollide(player, enemies, False) — при касании враг остаётся (удобно для урона или мигания)
  • spritecollide(bullet, enemies, True) — враг исчезает из групп
  • после попадания пулю часто вызывают bullet.kill() отдельно, если у пули dokill=False

Один спрайт в нескольких группах

Один и тот же объект в памяти можно положить в разные группы. У каждой группы своя задача:

  • all_sprites — общий update() и draw() в игровом цикле
  • enemies — проверка spritecollide(player, enemies, ...)
  • bullets — проверка groupcollide(bullets, enemies, ...)
  • players — отдельная логика (лидерборд, смена персонажа), если понадобится

Создание врага из практики выше:

patrol = Enemy()
all_sprites.add(patrol)
enemies.add(patrol)

Разбор на готовом шутере — Pygame в Lab, раздел shooter. Крупный проект со спрайтами — Python — Space Invaders.

update и draw у Group

all_sprites = pygame.sprite.Group()
all_sprites.add(player)

# каждый кадр в главном цикле:
all_sprites.update() # у каждого спрайта — свой update()
all_sprites.draw(screen) # screen.blit(image, rect) для всех членов
  • draw() копирует image на screen в позицию rect (операция blit)
  • если у спрайта нет image или rect, draw() для него пропустит кадр
  • порядок рисования в обычном Group не фиксирован; кто окажется сверху, может меняться от запуска к запуску
  • когда нужен стабильный порядок (фон, персонаж, интерфейс), берут LayeredUpdates — см. ниже и справочник

Функции столкновений

Pygame проверяет касания по-разному: от быстрых прямоугольников до проверки каждого пикселя.

ФункцияКогда применятьСкоростьТочность
collide_rect(a, b)Пули, тайлы, прямоугольные объектыВысокаяПо прямоугольнику rect
collide_circle(a, b)Шары, планеты, круглые спрайтыВысокаяПо вписанной окружности в rect
collide_mask(a, b)Персонажи со сложным силуэтом PNGНизкаяПо непрозрачным пикселям (маски в справочнике)
spritecollide(sprite, group, dokill)Игрок и группа врагов, пуля и врагиЗависит от функции проверкиСписок всех касаний
spritecollideany(sprite, group)Нужен ответ "коснулся ли хоть кто-то"Та жеОдин спрайт или None
groupcollide(g1, g2, dokill1, dokill2)Много пуль против многих враговТа жеСловарь пар столкновений

Проверка проигрыша без перебора списка попаданий:

if pygame.sprite.spritecollideany(player, enemies):
running = False

Если объект описан только pygame.Rect (сетка тайлов, невидимая зона двери), используйте rect1.colliderect(rect2) и rect1.collidepoint(x, y) — подробнее в разделе про Rect и в примере столкновений.

Опциональный аргумент collided — своя функция (спрайт_a, спрайт_b) -> bool. По умолчанию Pygame сравнивает rect. Для масок передают collided=pygame.sprite.collide_mask (справочник, §4).

Слои отрисовки (LayeredUpdates)

HUD (heads-up display) — текст и иконки поверх игры: счёт, жизни, пауза. Их нужно рисовать после фона и персонажа. LayeredUpdates сортирует спрайты по числу _layer: меньшее значение — ниже, большее — выше.

all_sprites = pygame.sprite.LayeredUpdates()

class Background(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((800, 600))
self.image.fill((30, 30, 50))
self.rect = self.image.get_rect()
self._layer = 0

class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((40, 40))
self.image.fill((255, 80, 0))
self.rect = self.image.get_rect(center=(400, 300))
self._layer = 10

class HudLabel(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
font = pygame.font.SysFont("arial", 24)
self.image = font.render("Score: 0", True, (255, 255, 255))
self.rect = self.image.get_rect(topleft=(10, 10))
self._layer = 100

all_sprites.add(Background(), Player(), HudLabel())
# draw() рисует сначала _layer=0, затем 10, затем 100

Текст на экране через pygame.font разобран в разделе про шрифты. Частичное обновление экрана (RenderUpdates, DirtySprite) — справочник по pygame.sprite.


Окно и поверхности (Surfaces)

Модуль display контролирует графическое окно. Центральным объектом выступает поверхность (Surface), возвращаемая функцией set_mode().

Функция set_mode(size, flags=0, depth=0) принимает кортеж размеров (ширина, высота). Флаги определяют режим отображения.

ФлагОписание
pygame.FULLSCREENРазворачивает окно на весь экран
pygame.RESIZABLEПозволяет пользователю менять размер окна
pygame.NOFRAMEУбирает рамку и заголовок окна
pygame.HIDDENСоздаёт окно в скрытом режиме

Центральным понятием в Pygame является поверхность (Surface) — двумерный массив пикселей, представляющий собой область рисования. Каждое изображение, текст или графический элемент в Pygame является экземпляром pygame.Surface.

# Создание новой поверхности размером 100x100 с прозрачностью
surf = pygame.Surface((100, 100), pygame.SRCALPHA)
surf.fill((255, 0, 0, 128)) # Красный цвет с полупрозрачностью

Главное окно игры создаётся с помощью pygame.display.set_mode(), которое возвращает объект Surface, связанный с экраном. Все последующие операции рисования (blitting) выполняются на этой или других поверхностях.


import pygame

screen = pygame.display.set_mode((800, 600))

Поверхности могут быть прозрачными (с альфа-каналом), иметь цветовой ключ (colorkey) для маскирования фона, а также подвергаться трансформациям — масштабированию, повороту, отражению.

Изменения на поверхности не отображаются автоматически. Требуется явный вызов функции обновления.

ФункцияОписание
pygame.display.flip()Обновляет весь экран. Подходит для двойной буферизации
pygame.display.update(rectangle)Обновляет указанную область экрана. Экономит ресурсы

Заголовок и иконка тоже могут быть изменены:

pygame.display.set_caption("Название игры")
icon = pygame.image.load("icon.png")
pygame.display.set_icon(icon)

Координатная система

В Pygame начало координат (0, 0) находится в левом верхнем углу экрана. Ось X направлена вправо. Ось Y направлена вниз.

Это отличается от стандартной математической системы, где Y направлен вверх. При расчёте физики необходимо учитывать инверсию оси Y.

Размеры окна задаются в пикселях. Координаты объектов хранятся в целых числах. Дробные координаты возможны внутри логики игры, но отрисовка требует целочисленных значений.


Рисование

Модуль draw содержит функции для рисования геометрических фигур непосредственно на поверхности.

ФункцияПараметрыОписание
rectsurface, color, rect, width=0Рисует прямоугольник. width=0 заполняет фигуру
polygonsurface, color, points, width=0Рисует многоугольник по списку точек
circlesurface, color, center, radius, width=0Рисует круг
ellipsesurface, color, rect, width=0Рисует эллипс внутри прямоугольника
arcsurface, color, rect, start_angle, stop_angle, width=1Рисует дугу
linesurface, color, start_pos, end_pos, width=1Рисует линию между двумя точками
linessurface, color, closed, points, width=1Рисует набор соединённых линий
aalinesurface, color, start_pos, end_pos, blend=1Рисует сглаженную линию
aalinessurface, color, closed, points, blend=1Рисует набор сглаженных линий

Пример рисования фигуры:

pygame.draw.rect(screen, (0, 255, 0), (50, 50, 100, 100))
pygame.draw.circle(screen, (0, 0, 255), (200, 200), 50)

Класс pygame.Rect хранит координаты и размеры прямоугольной области. Используется для позиционирования и проверки столкновений.

# Из координат и размеров
rect = pygame.Rect(x, y, width, height)
# Из поверхности
rect = surface.get_rect()
# Из кортежа
rect = pygame.Rect((10, 10, 50, 50))

Объект Rect обладает набором атрибутов для доступа к координатам сторон и углов.

АтрибутОписание
x, yКоординаты левого верхнего угла
width, heightРазмеры прямоугольника
top, left, bottom, rightКоординаты сторон
center, centerx, centeryКоординаты центра
topleft, topright, bottomleft, bottomrightКоординаты углов
midtop, midleft, midbottom, midrightКоординаты середин сторон
sizeКортеж (width, height)
w, hКороткие aliases для width и height

Методы Rect:

МетодОписание
colliderect(other_rect)Возвращает True при пересечении с другим Rect
collidepoint(x, y)Возвращает True, если точка внутри Rect
collidelist(list)Проверяет пересечение со списком Rect
move(x, y)Возвращает новый Rect, смещённый на x, y
move_ip(x, y)Смещает текущий Rect на x, y (in place)
clamp(other_rect)Перемещает Rect внутрь другого Rect
clip(other_rect)Возвращает пересечение двух Rect
union(other_rect)Возвращает объединение двух Rect
unionall(list)Возвращает объединение со списком Rect
fit(other_rect)Масштабирует и перемещает Rect внутрь другого
normalize()Исправляет отрицательную ширину или высоту

Текст и шрифты (font)

Модуль font позволяет рендерить текст на поверхностях. Текст в Pygame является изображением.

# Системный шрифт
font = pygame.font.SysFont("Arial", 24)
# Загрузка из файла
font = pygame.font.Font("file.ttf", 24)
# Шрифт по умолчанию
font = pygame.font.Font(None, 24)

Метод render(text, antialias, color, background=None) создаёт поверхность с текстом.

ПараметрОписание
textСтрока для отображения
antialiasBoolean. Сглаживание границ букв
colorЦвет текста (RGB или RGBA)
backgroundЦвет фона текста (опционально)

Пример вывода текста:

text_surface = font.render("Счёт: 10", True, (255, 255, 255))
screen.blit(text_surface, (10, 10))

Доступные свойства Font:

СвойствоОписание
get_height()Высота символов в пикселях
get_linesize()Высота строки
get_ascent()Подъём шрифта над базовой линией
get_descent()Спуск шрифта под базовую линию
size(text)Возвращает кортеж (width, height) текста
metrics(text)Возвращает метрики для каждого символа
set_bold(bool)Устанавливает жирное начертание
set_italic(bool)Устанавливает курсив
set_underline(bool)Устанавливает подчёркивание
get_bold(), get_italic(), get_underline()Возвращают статус стилей

События и ввод (event)

Система событий обрабатывает действия пользователя и системы. События помещаются в очередь.

for event in pygame.event.get():
# Обработка

Функция pygame.event.get() возвращает список событий за последний кадр. Функция pygame.event.poll() возвращает одно событие или pygame.NOEVENT.

Типы событий:

ТипОписание
pygame.QUITПользователь нажал кнопку закрытия окна
pygame.KEYDOWNКлавиша нажата
pygame.KEYUPКлавиша отпущена
pygame.MOUSEMOTIONДвижение мыши
pygame.MOUSEBUTTONDOWNНажатие кнопки мыши
pygame.MOUSEBUTTONUPОтпускание кнопки мыши
pygame.JOYAXISMOTIONДвижение оси геймпада
pygame.JOYBUTTONDOWNНажатие кнопки геймпада

Событие KEYDOWN содержит атрибут key (код клавиши) и mod (модификаторы Shift, Ctrl).

if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
jump()
if event.key == pygame.K_ESCAPE:
running = False

Постоянное состояние клавиш проверяется через pygame.key.get_pressed(). Возвращает кортеж булевых значений для всех клавиш.

keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= speed

Событие MOUSEBUTTONDOWN содержит атрибут button (1 - левая, 3 - правая, 2 - колесо). Атрибут pos содержит координаты (x, y).

if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
shoot(event.pos)

Текущая позиция мыши: pygame.mouse.get_pos(). Состояние кнопок: pygame.mouse.get_pressed().

Для геймпадов же требуется инициализация модуля pygame.joystick.

pygame.joystick.init()
joystick_count = pygame.joystick.get_count()
if joystick_count > 0:
joystick = pygame.joystick.Joystick(0)
joystick.init()

В цикле событий обрабатываются JOYAXISMOTION и JOYBUTTONDOWN. Оси возвращают значения от -1.0 до 1.0.


Время и частота кадров (time)

Модуль time контролирует скорость игры.

Объект pygame.time.Clock() регулирует частоту кадров.

clock = pygame.time.Clock()
# В конце цикла
clock.tick(60) # Ограничивает цикл 60 кадрами в секунду

Разбор фрагмента:

  • Clock() управляет темпом главного цикла.
  • tick(60) ограничивает частоту до 60 FPS, чтобы игра не перегружала CPU и шла с предсказуемой скоростью.
  • Возвращаемое значение tick можно использовать как delta-time для физики.

Метод tick(framerate) задерживает выполнение, чтобы достичь указанной частоты. Возвращает время в миллисекундах с прошлого вызова.

Функция pygame.time.get_ticks() возвращает время в миллисекундах с момента инициализации pygame.init(). Используется для таймеров.

start_time = pygame.time.get_ticks()
# В цикле
current_time = pygame.time.get_ticks()
if current_time - start_time > 1000:
print("Прошла секунда")
start_time = current_time

Функция pygame.time.delay(ms) приостанавливает программу на указанное время. pygame.time.wait(ms) работает аналогично, но блокирует события.


Изображения и звук

Модуль pygame.image загружает файлы в поверхности.

image = pygame.image.load("player.png")
# Конвертация формата для скорости
image = image.convert()
# Конвертация с прозрачностью
image = image.convert_alpha()

Поддерживемые форматы — PNG, JPG, BMP, GIF.

Модуль pygame.mixer управляет аудио.

Класс/ФункцияОписание
pygame.mixer.Sound(file)Загружает звуковой эффект в память
sound.play()Воспроизводит звук
sound.stop()Останавливает звук
sound.set_volume(val)Устанавливает громкость (0.0 - 1.0)
pygame.mixer.music.load(file)Загружает фоновую музыку (поток)
pygame.mixer.music.play(loops)Запускает музыку. loops=-1 для бесконечности
pygame.mixer.music.stop()Останавливает музыку
pygame.mixer.music.set_volume(val)Громкость музыки

Пример использования:

jump_sound = pygame.mixer.Sound("jump.wav")
jump_sound.play()

pygame.mixer.music.load("bgm.mp3")
pygame.mixer.music.play(-1)

Разбор фрагмента:

  • pygame.mixer.Sound(...) подходит для коротких эффектов и быстро воспроизводится по событию.
  • pygame.mixer.music.load(...) используется для фоновой дорожки.
  • play(-1) включает бесконечный цикл музыки, что типично для игрового бэкграунда.

Где брать графику и звук

В Практикуме и Lab первые проекты рисуют объекты примитивами:

  • pygame.draw.rect, circle, line;
  • цветные pygame.Rect без файлов с диска.

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

Куда класть файлы в проекте

  • рядом с main.py (например player.png);
  • или в подпапку assets/images/, assets/sounds/.

Загрузка в коде:

ship = pygame.image.load("assets/images/ship.png").convert_alpha()
shot = pygame.mixer.Sound("assets/sounds/laser.wav")

Подробнее про load, convert и mixer — в разделе Изображения и звук выше на этой странице.

Какие форматы обычно берут

НазначениеФорматПримечание
Спрайт персонажа или врагаPNGПрозрачный фон — после загрузки вызовите convert_alpha()
Фон уровняPNG или JPGДля JPG один раз convert() ускоряет отрисовку
Короткий эффект (выстрел, взрыв)WAV или OGGКласс pygame.mixer.Sound, воспроизведение по событию
Фоновая музыкаOGG или MP3Модуль pygame.mixer.music, можно зациклить play(-1)

Каталоги с бесплатными материалами

Перед скачиванием откройте страницу ассета и прочитайте лицензию (можно ли использовать в учебном проекте, нужно ли указать автора).

  • OpenGameArt.org — спрайты, тайлсеты, UI, наборы для 2D-аркад.
  • Kenney.nl — цельные паки в одном стиле ("Space Shooter", "Platformer"); удобно для прототипа.
  • itch.io, раздел game assets — бесплатные и donateware-наборы от инди-авторов.
  • Freesound.org — звуковые эффекты; часто лицензии Creative Commons.
  • Incompetech — фоновая музыка; в курсовой укажите автора Kevin MacLeod, если того требует лицензия.

Учёт авторства

Добавьте в репозиторий файл CREDITS.txt или блок в README.md:

  • имя автора ассета;
  • ссылка на страницу;
  • тип лицензии (CC0, CC-BY, MIT и т.д.).

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

Связанные учебные проекты


Цикл игры (Game Loop)

Игровой цикл — фундаментальная структура любой интерактивной программы. В Pygame он реализуется вручную и состоит из трёх этапов:

  • Обработка событий (Event Handling)
  • Обновление состояния игры (State Update)
  • Отрисовка (Rendering) Пример базового цикла:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

# Обновление логики
update_game_state()

# Отрисовка
screen.fill((0, 0, 0))
draw_objects(screen)
pygame.display.flip()

Цикл выполняется с максимально возможной частотой, обычно ограниченной с помощью pygame.time.Clock, чтобы обеспечить стабильный FPS (например, 60 кадров в секунду).


События (Events)

Pygame использует систему очереди событий. Все внешние воздействия — нажатия клавиш, движения мыши, закрытие окна — помещаются в очередь и обрабатываются в цикле через pygame.event.get().

События являются объектами с атрибутами type (тип события) и, опционально, дополнительными данными (key, pos, button и т.д.). Это позволяет реализовать реактивную архитектуру, где игра реагирует на пользовательский ввод асинхронно.

for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.jump()

Спрайты и группы — краткая сводка

Маршрут по теме в этой главе:

  1. Простое управление спрайтом — первый Sprite, клавиши, Group
  2. Враги, столкновения, снарядыspritecollide, groupcollide, kill()
  3. Архитектура pygame.sprite — термины, таблица коллизий, LayeredUpdates

Дополнительно:


Столкновения без спрайтов

Не каждый объект обязан наследовать Sprite. Иногда достаточно pygame.Rect:

  • Тайловая карта — прямоугольник каждой клетки сетки (тайловый фон)
  • Зона двери или триггера — невидимый Rect; при входе игрока меняется уровень
  • Клик по кнопке менюrect.collidepoint(x, y) с координатами мыши

Основные методы Rect:

  • rect1.colliderect(rect2) — пересекаются ли два прямоугольника
  • rect1.collidepoint(x, y) — попала ли точка внутрь

Для игровых персонажей и пуль удобнее модуль pygame.spriteтаблица функций. Пиксельная точность по PNG — collide_mask и pygame.mask.from_surface() в справочнике.


Звуки и музыка

Pygame поддерживает воспроизведение аудиофайлов через модули pygame.mixer и pygame.mixer.music.

  • pygame.mixer.Sound — для коротких эффектов (выстрел, прыжок).
  • pygame.mixer.music — для фоновой музыки (поддерживает потоковое воспроизведение).
jump_sound = pygame.mixer.Sound("jump.wav")
jump_sound.play()

pygame.mixer.music.load("background.mp3")
pygame.mixer.music.play(-1) # зацикливание

Поддерживаются форматы WAV, MP3, OGG. Однако качество и стабильность воспроизведения зависят от платформы и бэкенда SDL.

Пример: реализация "Змейки". Это классический пример, демонстрирующий работу с циклом, вводом, отрисовкой и логикой столкновений.

Основные компоненты:

  • Состояние змейки: список координат её сегментов.
  • Направление движения: вектор (dx, dy).
  • Еда: случайно генерируемая позиция.
  • Условия завершения: выход за границы поля или самопересечение.

Полный код:

Код ITЗагрузка примера кода…

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

Для серьёзных проектов рекомендуется использовать специализированные игровые движки — Godot, Unity, Unreal. Однако для обучения, прототипирования или реализации простых 2D-игр Python с Pygame остаётся практичным и доступным выбором.


Практические примеры реализации

Вывод текста на экран

Создание функции для централизованного вывода текста упрощает код.

def draw_text(surface, text, size, x, y):
font = pygame.font.SysFont("serif", size)
text_surface = font.render(text, True, (255, 255, 255))
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surface.blit(text_surface, text_rect)

Создание спрайта игрока с анимацией

Анимация реализуется через смену изображений по таймеру.

Код ITЗагрузка примера кода…


Спрайт противника и движение

Любое перемещение врага выполняется только в update(), пока в главном цикле вызывается all_sprites.update(). Ниже — типичные паттерны; выберите один под механику игры.

Падение сверху (как в аркадах вроде Space Invaders):

Код ITЗагрузка примера кода…

Отскок по горизонтали — смена direction у границ экрана (см. пошаговый пример выше).

Преследование игрока — сравнение координат rect с целью:

Код ITЗагрузка примера кода…

При одновременном сдвиге по X и Y враг по диагонали движется примерно в 1,4 раза быстрее (сумма двух осей). Для одинаковой скорости в любом направлении нормализуйте вектор:

dx = self.player.rect.centerx - self.rect.centerx
dy = self.player.rect.centery - self.rect.centery
length = (dx ** 2 + dy ** 2) ** 0.5
if length > 0:
self.rect.x += int(dx / length * self.speed)
self.rect.y += int(dy / length * self.speed)

Удобная альтернатива — pygame.math.Vector2 для векторов скорости и нормализации.


Платформа с коллизией

Проверка столкновения игрока с платформой требует проверки направления движения.

Код ITЗагрузка примера кода…


Пуля или снаряд

Снаряд — отдельный спрайт с направлением (vx, vy). Метод kill() удаляет его из всех групп, в которые он входил.

Фиксированное направление (например, вправо по SPACE):

Код ITЗагрузка примера кода…

Выстрел в сторону курсора — вектор от центра игрока к event.pos, нормализация длины, затем создание Bullet с компонентами скорости (см. пошаговый раздел выше).

Попадание по врагам:

hits = pygame.sprite.groupcollide(bullets, enemies, True, True)
# dokill для пуль True, для врагов True — оба удаляются при столкновении

Для спрайтов со сложной формой вместо rect можно использовать pygame.sprite.collide_mask и маски pygame.mask.from_surface() — см. справочник по pygame.sprite.


Бонусы и сбор предметов

Бонусы исчезают при касании игрока.

Код ITЗагрузка примера кода…


Реакция на клик мыши

Спавн объекта в месте клика.

for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Левая кнопка
pos = pygame.mouse.get_pos()
effect = Effect(pos[0], pos[1])
all_sprites.add(effect)

Передвижение спрайта с ускорением

Использование векторов скорости и ускорения.

Код ITЗагрузка примера кода…


Вывод сообщений и экран Game Over

Отрисовка поверх игрового процесса.

def draw_game_over(screen):
font = pygame.font.SysFont("Arial", 64)
text = font.render("GAME OVER", True, (255, 0, 0))
rect = text.get_rect(center=(400, 300))
screen.blit(text, rect)

font_small = pygame.font.SysFont("Arial", 24)
text_small = font_small.render("Нажмите R для рестарта", True, (255, 255, 255))
rect_small = text_small.get_rect(center=(400, 350))
screen.blit(text_small, rect_small)

Включение и выключение звуков

Управление микшером через клавиши.

for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_m:
if pygame.mixer.music.get_busy():
pygame.mixer.music.pause()
else:
pygame.mixer.music.unpause()
if event.key == pygame.K_s:
volume = pygame.mixer.Sound.get_volume()
if volume > 0:
pygame.mixer.Sound.set_volume(0)
else:
pygame.mixer.Sound.set_volume(1)

Полный пример структуры игры

Код ниже объединяет описанные компоненты в единую систему.

Код ITЗагрузка примера кода…


Play

Библиотека play — сторонняя библиотека, разработанная для упрощения создания 2D-игр и анимаций, особенно в образовательной среде. Она строится на основе Pygame Zero, но предлагает ещё более минималистичный API, ориентированный на начинающих. Установка проста:

pip install play

play следует императивной модели, в которой программа описывает поведение объектов в виде функций обратного вызова (update, draw). Главный цикл управления выполняется автоматически.

Центральным элементом являются спрайты — двухмерные объекты, обладающие позицией, размером, изображением и свойствами анимации. Спрайт создаётся как экземпляр класса play.new_image() или play.new_box():

ball = play.new_circle(color="red", x=0, y=0, radius=25)

Каждый спрайт имеет атрибуты:

  • x, y — координаты центра.
  • angle — угол поворота.
  • size — масштаб относительно исходного изображения.
  • image — если используется текстура.
  • visible — видимость объекта.

Движение реализуется путём изменения атрибутов спрайтов в функции update(), которая вызывается каждый кадр (обычно 60 раз в секунду):

@play.repeat_forever
def do():
ball.x += 1

Реакция на события оформляется декораторами — без ручного разбора очереди, как в Pygame:

Код ITЗагрузка примера кода…

Также доступны встроенные методы, такие как move(), point_towards(), rotate().

Обнаружение столкновений (коллизий) выполняется с помощью метода is_touching(other_sprite):

if ball.is_touching(paddle):
ball.color = "blue"

Этот метод проверяет пересечение границ спрайтов (bounding boxes), что достаточно для большинства простых случаев, но не учитывает прозрачные области изображений.

play предоставляет простой доступ к состоянию клавиш:

if play.key_is_pressed("w"):
paddle.y += 5

Поддерживаются буквенные, цифровые и специальные клавиши ("space", "up", "left" и т. д.). Нет необходимости вручную управлять event loop — библиотека делает это автоматически.

Рассмотрим минимальную реализацию игры, где игрок должен перемещать платформу, чтобы поймать падающий шарик.

Код ITЗагрузка примера кода…

Этот пример демонстрирует типичную структуру приложения в play — объявление объектов, реакция на события в цикле repeat_forever, использование глобального состояния.


Распространённые механики в Pygame

Обработка столкновений (Collision Detection)

Функции pygame.sprite для спрайтов и сравнение способов проверки — в разделе про столкновения спрайтов. Ниже — отдельный пример на чистых pygame.Rect и кругах (полезно для платформ и физики без классов-наследников).

Код ITЗагрузка примера кода…


Система частиц (Particle System)

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

Код ITЗагрузка примера кода…


Тайловый фон (Tilemap)

Для создания уровня без рисования каждого пикселя вручную используется сетка тайлов. Каждый элемент сетки — это картинка (тайл), которая повторяется.

Код ITЗагрузка примера кода…


Камера (Camera Follow)

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

Код ITЗагрузка примера кода…


Простой инвентарь (Grid UI)

Создание сетки для отображения предметов. Это база для RPG или стратегий. Мы используем Rect для определения слотов и проверку кликов мыши.

Код ITЗагрузка примера кода…


Анимация спрайта (Sprite Sheet)

Использование одного изображения (спрайт-листа), где содержатся все кадры анимации, и переключение видимых частей.

Примечание: Для примера мы генерируем картинку программно, но в реальном проекте вы загружаете файл .png.

Код ITЗагрузка примера кода…


Пауза и Меню (Game State Management)

Управление состоянием игры позволяет переключаться между "Игрой", "Паузой" и "Меню". Это реализуется через флаг состояния (game_state).

Код ITЗагрузка примера кода…


Система здоровья с визуальным эффектом (Hit Flash)

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

Код ITЗагрузка примера кода…


Сохранение и загрузка данных (JSON)

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

Код ITЗагрузка примера кода…


Практика и справочник


В подборках

Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:

Разработка видеоигрПрактикум — о разделе, Веб-игры на HTML5 и Canvas, Разработка игр — о разделе, Разработка игр с использованием C++, Игровая индустрия — о разделе, Игроведение — о разделе.


Содержание