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

Анимация в Pygame — полное руководство

5 min read Разработка игр Обновлено 20 Dec 2025
Анимация в Pygame — полное руководство
Анимация в Pygame — полное руководство

Кратко: научитесь добавлять плавную анимацию в игры на Pygame — от простого переключения кадров до использования sprite sheets, управления скоростью и оптимизации. В материале есть готовые примеры кода, чек‑листы для разработчика и сценарии тестирования.

мужчина создает анимацию для игры

Введение

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

Важно: термины

  • Спрайт — изображение или объект, отображаемый в игре.
  • Кадр (frame) — отдельное изображение в последовательности анимации.
  • Sprite sheet — одна большая картинка, содержащая несколько кадров.

Создаём простую игру — структура проекта

Начнём с минимальной игры, где игрок может двигаться влево/вправо по платформе. Это даёт контекст для анимации. Принцип: загружаем кадры в память заранее, обновляем позицию игрока по вводу и рисуем текущий кадр на экране.

Примечание: исходный код, использованный в статье, доступен в репозитории GitHub под MIT‑лицензией (ссылка в оригинале). Ниже — полные примеры файлов, которые можно взять за основу.

Пример: simple-game.py

Ниже минимальный рабочий пример, иллюстрирующий ввод и отрисовку базовой игровой сцены. Скопируйте в simple-game.py.

import pygame
import sys

pygame.init()
WIDTH, HEIGHT = 640, 360
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

# Игрок
player_x, player_y = 100, 200
player_speed = 3

# Платформа
platform_x, platform_y = 0, 280
platform_width, platform_height = WIDTH, 80

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 -= player_speed
    if keys[pygame.K_RIGHT]:
        player_x += player_speed

    screen.fill((50, 50, 60))
    pygame.draw.rect(screen, (120, 80, 40), (platform_x, platform_y, platform_width, platform_height))
    pygame.draw.rect(screen, (200, 50, 50), (player_x, player_y, 20, 20))

    pygame.display.flip()
    clock.tick(60)

pygame.quit()
sys.exit()

Результат должен выглядеть примерно так:

простая игра с игроком и платформой

Загрузка и отображение кадров

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

Ниже — упрощённый пример создания трёх кадров и их отрисовки. Это можно вынести в отдельный файл animate.py или включить в основной код.

import pygame

# Предполагаем, что pygame уже инициализирован и есть screen
# Создание тестовых кадров (вместо загрузки с диска)
frame0 = pygame.Surface((20, 20), pygame.SRCALPHA)
frame0.fill((255, 0, 0))

frame1 = pygame.Surface((20, 20), pygame.SRCALPHA)
frame1.fill((0, 255, 0))

frame2 = pygame.Surface((20, 20), pygame.SRCALPHA)
frame2.fill((0, 0, 255))

frames = [frame0, frame1, frame2]
current_frame = frames[0]

# В игровом цикле:
# screen.blit(current_frame, (player_x, player_y))
# pygame.display.flip()

Управление анимацией с вводом игрока

Чтобы персонаж выглядел живым при движении, переключайте кадры в зависимости от ввода. Это может быть простая логика «стоячий/идёт влево/идёт вправо» или полноценный автомат с состояниями.

# Пример внутри игрового цикла
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
    player_x -= player_speed
    current_frame = frames[1]
elif keys[pygame.K_RIGHT]:
    player_x += player_speed
    current_frame = frames[2]
else:
    current_frame = frames[0]

screen.blit(current_frame, (player_x, player_y))

Выход (пример):

анимированный игрок на платформе

Sprite sheets — извлечение кадров из единого изображения

Sprite sheet — удобный формат для сохранения всех кадров в одном файле. Ниже функция, которая разрезает лист на отдельные pygame.Surface.

import pygame

def extract_frames(sheet: pygame.Surface, frame_width: int, frame_height: int):
    """Возвращает список кадров, вырезанных слева направо, сверху вниз."""
    frames = []
    sheet_width, sheet_height = sheet.get_size()
    cols = sheet_width // frame_width
    rows = sheet_height // frame_height
    for y in range(rows):
        for x in range(cols):
            rect = pygame.Rect(x * frame_width, y * frame_height, frame_width, frame_height)
            frame = pygame.Surface((frame_width, frame_height), pygame.SRCALPHA)
            frame.blit(sheet, (0, 0), rect)
            frames.append(frame)
    return frames

# Пример использования:
# sprite_sheet = pygame.image.load("spritesheet.png").convert_alpha()
# frames = extract_frames(sprite_sheet, 32, 32)

Совет: используйте convert_alpha() для изображений с прозрачностью — это улучшает производительность при отрисовке.

Управление скоростью анимации

Часто нужно, чтобы кадры сменялись не на каждом кадре игры, а с определённой задержкой. Для этого используйте pygame.time.Clock или pygame.time.get_ticks().

animation_delay = 120  # миллисекунд между кадрами
last_frame_time = pygame.time.get_ticks()
frame_index = 0

# В игровом цикле:
current_time = pygame.time.get_ticks()
if current_time - last_frame_time >= animation_delay:
    frame_index = (frame_index + 1) % len(frames)
    current_frame = frames[frame_index]
    last_frame_time = current_time

screen.blit(current_frame, (player_x, player_y))

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

Детекция столкновений

Pygame предоставляет удобный метод Rect.colliderect для простых прямоугольных столкновений. Для более точной проверки можно использовать маски (pygame.mask) для пиксельной коллизии.

def check_collision(player_rect: pygame.Rect, platform_rect: pygame.Rect) -> bool:
    return player_rect.colliderect(platform_rect)

# В цикле:
player_rect = pygame.Rect(player_x, player_y, 20, 20)
platform_rect = pygame.Rect(platform_x, platform_y, platform_width, platform_height)
if check_collision(player_rect, platform_rect):
    # обработка столкновения: остановить падение, расположить игрока на платформе и т.п.
    pass

Если нужны более точные столкновения между не прямоугольными спрайтами, создавайте pygame.mask.Mask через Surface.

Использование pygame.sprite.Sprite и Group

Класс Sprite упрощает управление объектами: обновление, отрисовка и группировка. Ниже схема простого игрового спрайта с анимацией.

class Player(pygame.sprite.Sprite):
    def __init__(self, frames):
        super().__init__()
        self.frames = frames
        self.image = frames[0]
        self.rect = self.image.get_rect(topleft=(100, 200))
        self.frame_index = 0
        self.last_frame_time = pygame.time.get_ticks()

    def update(self, dt, keys):
        # движение
        if keys[pygame.K_LEFT]:
            self.rect.x -= 3
            self.image = self.frames[1]
        elif keys[pygame.K_RIGHT]:
            self.rect.x += 3
            self.image = self.frames[2]
        else:
            self.image = self.frames[0]

        # можно добавить автоматическое переключение кадров по времени

Group помогает вызывать update() и draw() для всех спрайтов разом.

Лучшие практики и оптимизация

  • Предзагружайте кадры до запуска цикла игры. Это убирает I/O в loop и предотвращает рывки.
  • Используйте .convert() или .convert_alpha() после загрузки изображений для ускорения blit.
  • Минимизируйте частые аллокации Surface внутри цикла; создавайте поверхности заранее.
  • Ограничивайте частоту обновления экрана с помощью Clock.tick(fps).
  • Старайтесь рисовать только изменённые области (для сложных сцен) или используйте OG/Canvas подход.
  • Для мобильных платформ уменьшайте размер кадров и используйте спрайт‑атласы с оптимальным сжатием.

Important: профилируйте ваш код в целевой среде. «Быстро на локальной машине» не значит «быстро на слабом ноутбуке».

Чек‑лист при разработке анимации

  • Все кадры предзагружены и конвертированы (.convert/_alpha).
  • Animation delay вынесен в настраиваемую переменную.
  • Состояния персонажа (idle/walk/jump) покрыты кадрами.
  • Обработка столкновений корректно реагирует на позиции после отрисовки.
  • Нет создания Surface в основном цикле.
  • Проверена производительность при целевой частоте кадров.

Роли и задачи

  • Художник: экспортирует sprite sheets, даёт метаданные (ширина/высота кадра, количество кадров).
  • Разработчик: реализует извлечение кадров, state machine, и оптимизацию загрузки.
  • QA: проверяет анимации на разных скоростях и разрешениях, ищет дерганья и смещения.

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

  • Персонаж плавно переключает кадры при движении на минимально допустимом железе.
  • Нет видимых задержек при смене сцен или повторном входе в экран.
  • Коллизии корректны в 95% игровых сценариев (при тестировании ручными кейсами).
  • Ресурсы (память/VRAM) используются прогнозируемо — подозрительные всплески памяти отсутствуют.

Тестовые случаи (acceptance)

  • Двигаться влево/вправо — анимация должна корректно сменяться.
  • Стоять на месте — отображается idle‑кадр.
  • Быстрый спринт — скорость анимации увеличена.
  • Столкновение с платформой — персонаж должен стать «на платформу», не провалиться.
  • Появление и исчезновение спрайта — без утечек ресурсов.

Частые ошибки и как их избежать

  • Ошибка: загрузка изображений в цикле — решение: загрузка в init / до цикла.
  • Ошибка: неиспользование convert_alpha() для PNG с прозрачностью — решение: применять convert_alpha().
  • Ошибка: жесткая привязка логики анимации к fps — решение: использовать время (ticks) вместо кадров.

Короткий глоссарий (1 строка на термин)

  • FPS — количество кадров в секунду, определяет плавность рендера.
  • Frame — отдельное изображение в последовательности анимации.
  • Sprite sheet — изображение, содержащее набор кадров.
  • Rect — прямоугольник, используемый для позиционирования и столкновений.
  • Mask — битовая маска поверхности для пиксельной коллизии.

Советы по совместимости и переносимости

  • Проверяйте поведение на целевых платформах (Windows/Linux/macOS). Pygame основан на SDL и может вести себя по‑разному в зависимости от драйверов графики.
  • Если планируется порт на мобильные устройства, минимизируйте разрешение текстур и используйте масштабирование на уровне рендера.

Заключение

Анимация в Pygame — сочетание корректной организации ресурсов (sprite sheets, предзагрузка), привязки логики к реальному времени и применения простых структур (Sprite, Group, Rect). Начните с простого переключения кадров по вводу, затем плавно развивайте систему: добавьте state machine, тайминги, оптимизации и тесты. Экспериментируйте с художественной подачей и поведением — именно это делает игру запоминающейся.

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

  • Предзагружайте и конвертируйте изображения.
  • Управляйте скоростью анимации через время, а не через кадры.
  • Используйте sprite sheets и pygame.sprite для упрощения кода.
  • Тестируйте производительность на целевых устройствах.

Спасибо за чтение — пробуйте, комбинируйте техники и делитесь результатами с сообществом.

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

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

Как экономить мобильные данные в Apple Music
Мобильные данные

Как экономить мобильные данные в Apple Music

Персональные результаты Google Assistant на блокировке
Android.

Персональные результаты Google Assistant на блокировке

Настройка уведомлений Outlook: отключить и адаптировать
Справка

Настройка уведомлений Outlook: отключить и адаптировать

Добавить дату и время в Google Sheets
Электронные таблицы

Добавить дату и время в Google Sheets

Таймер Помодоро на Python с Tkinter
Python

Таймер Помодоро на Python с Tkinter

Как отключить 5G на Android — Samsung и Pixel
Android.

Как отключить 5G на Android — Samsung и Pixel