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

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

5 min read Разработка игр Обновлено 04 Jan 2026
Анимация в Pygame — плавные игровые спрайты
Анимация в Pygame — плавные игровые спрайты

Разработчик создаёт анимации для игры

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

Создание простой игры

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

В репозитории на GitHub (см. исходники проекта) приведён пример под лицензией MIT — вы можете использовать код в своих проектах.

Принципиально вам нужны переменные для позиции и скорости игрока и платформы, а также обработка ввода через pygame.key.get_pressed(). При нажатии стрелки влево уменьшаем player_x, при нажатии вправо — увеличиваем. Это создаёт движение спрайта.

Пример: минимальная сцена с игроком и платформой.

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

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

Анимация в 2D достигается последовательной отрисовкой разных изображений (кадров). На базовом уровне предположим три кадра: frame0, frame1, frame2. Изначально показываем frame0.

Создайте файл animate.py и добавьте следующий фрагмент (пример из простого подхода):

  
# Load frames  
frame0 = pygame.Surface((20, 20))  
frame0.fill((255, 0, 0))  
  
frame1 = pygame.Surface((20, 20))  
frame1.fill((0, 255, 0))  
  
frame2 = pygame.Surface((20, 20))  
frame2.fill((0, 0, 255))  
  
# Set initial frame  
current_frame = frame0  
  
# Game loop  
while running:  
    # ...  
  
    # Render the game  
    # ...  
    screen.blit(current_frame, (player_x, player_y))    
  
    pygame.display.flip()  
  
# ...

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

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

Чтобы спрайт «ходил», переключайте кадры в ответ на ввод. Ниже — упрощённый цикл, где движение по стрелкам меняет текущий кадр.

# Game loop  
while running:  
    # ...  
  
    # Handle player input  
    keys = pygame.key.get_pressed()  
    if keys[pygame.K_LEFT]:  
        player_x -= player_speed  
        current_frame = frame1  
    elif keys[pygame.K_RIGHT]:  
        player_x += player_speed  
        current_frame = frame2  
    else:  
        current_frame = frame0  
  
    # Render the game  
    # ...  
    screen.blit(current_frame, (player_x, player_y))    
  
    pygame.display.flip()  
  
# ...

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

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

Дополнительные возможности

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

Sprite sheets

Sprite sheet — одна картинка, содержащая множество кадров. Извлечение кадров из sprite sheet ускоряет загрузку и упрощает версионирование артов.

Пример функции извлечения кадров из sprite sheet:

# Load the sprite sheet image  
sprite_sheet = pygame.image.load("spritesheet.png")  
  
# Define the dimensions of each frame  
frame_width = 32  
frame_height = 32  
  
# Function to extract frames from the sprite sheet  
def extract_frames(sheet, frame_width, frame_height):  
    frames = []  
    sheet_width, sheet_height = sheet.get_size()  
    for y in range(0, sheet_height, frame_height):  
        for x in range(0, sheet_width, frame_width):  
            frame = pygame.Surface((frame_width, frame_height), pygame.SRCALPHA)  
            frame.blit(sheet, (0, 0), (x, y, frame_width, frame_height))  
            frames.append(frame)  
    return frames  
  
# Extract frames from the sprite sheet  
frames = extract_frames(sprite_sheet, frame_width, frame_height)  
  
# Display a frame from the sprite sheet  
current_frame = frames[0]  
  
# Game loop  
while running:  
    # ...  
    screen.blit(current_frame, (player_x, player_y))    
    # ...

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

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

Контроль задержки между кадрами позволяет добиваться плавности. Вместо жёсткой привязки к fps лучше отделять таймер анимации от общей частоты кадров.

Пример с использованием pygame.time.get_ticks() и pygame.time.Clock():

# Animation speed variables  
animation_delay = 100 # Delay in milliseconds between frame updates  
last_frame_time = pygame.time.get_ticks()  
frame_index = 0  
  
clock = pygame.time.Clock()  
  
# Game loop  
while running:  
    dt = clock.tick(60)  # ограничиваем до 60 FPS, dt в миллисекундах  
    # ...  
  
    # Check if enough time has passed to update the frame  
    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  
  
    # Render the game  
    # ...  
    screen.blit(current_frame, (player_x, player_y))    
  
    pygame.display.flip()

Вы можете регулировать animation_delay в зависимости от состояния (идёт бег — меньше задержка, стоит — больше).

Обнаружение столкновений

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

# Collision detection  
def check_collision(player_rect, platform_rect):  
    if player_rect.colliderect(platform_rect):  
        # Collision occurred  
        return True  
    else:  
        return False  
  
# Game loop  
while running:  
    # ...  
  
    # Perform collision detection  
    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):  
        # Handle collision  
        # Например, скорректировать player_y и обнулить вертикальную скорость  
  
    # Render the game  
    # ...  
    screen.blit(current_frame, (player_x, player_y))  
  
    pygame.display.flip()

Для точного столкновения используйте маски (pygame.mask) для нечётких форм, а не только rect.

Паттерны анимации и машина состояний

В реальных проектах удобно описывать анимации через состояния: idle, walk, run, jump, attack. Переключение состояний управляет не только кадром, но и логикой столкновений и звуков.

Пример простого менеджера анимации и спрайта:

class AnimatedSprite(pygame.sprite.Sprite):
    def __init__(self, frames_dict, pos=(0,0)):
        super().__init__()
        self.frames = frames_dict  # {'idle':[...], 'walk':[...], ...}
        self.state = 'idle'
        self.frame_index = 0
        self.image = self.frames[self.state][0]
        self.rect = self.image.get_rect(topleft=pos)
        self.last_update = pygame.time.get_ticks()
        self.anim_delay = 100

    def set_state(self, state):
        if state != self.state:
            self.state = state
            self.frame_index = 0
            self.last_update = pygame.time.get_ticks()

    def update(self):
        now = pygame.time.get_ticks()
        if now - self.last_update >= self.anim_delay:
            self.frame_index = (self.frame_index + 1) % len(self.frames[self.state])
            self.image = self.frames[self.state][self.frame_index]
            self.last_update = now

Такой подход упрощает добавление новых состояний и тестирование.

Лучшие практики

  • Предзагружайте кадры: загрузка с диска в цикле рендеринга тормозит игру. Загружайте всё при запуске сцены.
  • Используйте convert()/convert_alpha() на загруженных изображениях для ускорения отрисовки.
  • Группы спрайтов (pygame.sprite.Group) упрощают обновление и отрисовку.
  • Разделяйте частоту обновления логики (physics) и анимации от частоты рендеринга, где нужно.
  • Оптимизируйте форматы: PNG для прозрачности, JPEG для больших бэкграундов без прозрачности.
  • Для мобильных платформ экономьте память: объединяйте спрайты в sprite sheets и используйте атласы.

Мини-методология: добавить анимацию шаг за шагом

  1. Нарисуйте ключевые кадры (artist).
  2. Подготовьте sprite sheet или отдельные файлы (pipeline).
  3. Напишите код загрузки и предзагрузки кадров.
  4. Создайте AnimatedSprite с состояниями.
  5. Привяжите состояния к вводу и физике (movement → state).
  6. Тестируйте на разной частоте кадров и устройствах.

Чек-лист по ролям

  • Разработчик: загрузка картинок, оптимизация (convert), управление таймингом, тестирование на разных FPS.
  • Художник: единый стиль кадров, одинаковые размеры фреймов, отступы на sprite sheet.
  • Тестировщик: проверить все состояния, убедиться в отсутствии «телепортации» при смене кадров, проверка коллизий.

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

  • Анимация плавная при 60 FPS без проседаний.
  • При смене состояния нет мерцания и смещений спрайта.
  • Коллизии корректно обнаруживаются и корректируют позицию игрока.
  • Память и FPS в пределах приемлемых для целевой платформы.

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

  1. Игрок идёт влево — показывается анимация walk-left и позиция смещается на player_speed.
  2. Игрок стоит — состояние idle и один статический кадр.
  3. Прыжок — вертикальная скорость изменяется, кадры jump проигрываются один раз.
  4. Столкновение с платформой — игрок не проваливается и отталкивается корректно.

Шпаргалка (cheat sheet)

  • Класс: pygame.Surface((w,h), pygame.SRCALPHA) — поверхность с альфой.
  • Конвертация: img = pygame.image.load(path).convert_alpha()
  • Clock: clock = pygame.time.Clock(); dt = clock.tick(60)
  • Таймер: now = pygame.time.get_ticks()
  • Rect: r = pygame.Rect(x,y,w,h)
  • Маска: mask = pygame.mask.from_surface(surface)

Риски и смягчения

  • Проблема: лаг при загрузке изображений в рантайме.
    Смягчение: предзагрузка и прогресс-бар загрузки.
  • Проблема: слишком большой sprite sheet тормозит загрузку.
    Смягчение: разбить на более мелкие атласы.

Короткий глоссарий

  • Кадр (frame): одно изображение в последовательности анимации.
  • Sprite sheet: изображение, содержащее несколько кадров.
  • Frame rate (FPS): частота обновления экрана.
  • Mask: битовая маска для точной проверки столкновений.

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

Резюме

  • Анимация делает игру живой — начните с простого отображения кадров и переходите к sprite sheet и машинам состояний.
  • Предзагружайте ресурсы, управляйте таймингом через get_ticks() и Clock, используйте pygame.sprite для организации кода.
  • Итерируйте: художник и программист должны согласовывать размеры и долготу кадров, а тестировщик — проверять на целевых FPS.

Если нужно, могу добавить готовые примеры кода для конкретной архитектуры проекта (например, ECS или паттерн MVC), или подготовить «playbook» для команды из трёх человек.

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

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

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство