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

Прокручиваемые фоны и параллакс в Pygame

6 min read Разработка игр Обновлено 05 Jan 2026
Параллакс и прокрутка фонов в Pygame
Параллакс и прокрутка фонов в Pygame

Игровая сцена на широком мониторе с геймпадом

Прокручиваемые фоны повышают визуальную глубину игры и создают ощущение движения в мире. Их реализация в Pygame несложна: достаточно регулярно смещать фоновые слои по оси X (или Y) и при необходимости перезапускать их позицию для бесконечной прокрутки.

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

Что вы получите из этого руководства

  • Пошаговые рабочие примеры: simple-game.py, scrolling-bg.py, parallax.py.
  • Как быстро перейти от однослойного фона к многослойной параллакс-сцене с картинками.
  • Набор практических советов по производительности, масштабированию и тестированию.
  • Чек-листы ролей (разработчик, художник, тестировщик), мерч-схему принятия решений и примеры тест-кейсов.

Зависимости и подготовка

  • Убедитесь, что установлен Python 3.7+ и Pygame (pip install pygame).
  • Определите разрешение окна и целевые устройства. В коде ниже используются переменные screen_width и screen_height.

Важно: при использовании изображений заранее подготовьте версии, масштабированные под целевые разрешения (см. раздел «Оптимизация»).

Простая игра: перед тем как добавить фон

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

# simple-game.py
import pygame
import sys

pygame.init()

screen_width, screen_height = 800, 450
screen = pygame.display.set_mode((screen_width, screen_height))
clock = pygame.time.Clock()

# Игрок
player_x, player_y = 100, screen_height - 150
player_w, player_h = 32, 48
player_speed = 4

# Платформы
rect1 = pygame.Rect(50, screen_height - 100, 200, 10)
rect2 = pygame.Rect(screen_width - 250, screen_height - 200, 200, 10)

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

    screen.fill((30, 30, 30))
    pygame.draw.rect(screen, (0, 255, 0), rect1)
    pygame.draw.rect(screen, (0, 255, 0), rect2)
    pygame.draw.rect(screen, (255, 200, 0), (player_x, player_y, player_w, player_h))

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

pygame.quit()
sys.exit()

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

Простой игровой экран: игрок и платформы

Несколько фонов: модель слоёв

Идея простая: создайте список фоновых слоёв, каждому слою назначьте цвет (или изображение) и скорость. Быстрые слои находятся ближе к камере; медленные — дальше.

Пример определения прямоугольных фоновых слоёв:

background_layers = [
    pygame.Rect(0, 0, screen_width, screen_height),
    pygame.Rect(0, 0, screen_width, screen_height)
]

background_colors = [(30, 30, 30), (60, 60, 60)]
background_speeds = [0.1, 1.0]

Каждый элемент background_layers покрывает весь экран. Скорости задают относительное смещение по кадру. Значения скоростей подбирайте эмпирически: слои заднего плана — малые дробные значения, переднего плана — большие целые.

Прокрутка фона: логика обновления

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

for i in range(len(background_layers)):
    background_layers[i].x -= background_speeds[i]

    if background_layers[i].x <= -screen_width:
        background_layers[i].x = 0

    pygame.draw.rect(screen, background_colors[i], background_layers[i])

Объяснение: каждый кадр сдвигаем слой влево. Когда его левый край ушёл за предел экрана, возвращаем x к 0. В простейшей схеме это работает, если слой покрывает весь экран и выглядит непрерывно.

Игра: игрок, платформа и прокручиваемый фон

Параллакс при движении игрока

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

Пример структуры платформ со скоростью и обновлением в цикле:

# Определение платформ
rect1 = pygame.Rect(50, screen_height - 100, 200, 10)
rect2 = pygame.Rect(screen_width - 250, screen_height - 200, 200, 10)

platforms = [
    {"rect": rect1, "speed": 3},
    {"rect": rect2, "speed": 1}
]

# В игровом цикле
keys = pygame.key.get_pressed()

if keys[pygame.K_LEFT] and player_x > 0:
    player_x -= player_speed
    for platform in platforms:
        platform["rect"].x -= platform["speed"]

if keys[pygame.K_RIGHT] and player_x < screen_width:
    player_x += player_speed
    for platform in platforms:
        platform["rect"].x += platform["speed"]

for platform in platforms:
    pygame.draw.rect(screen, (0, 255, 0), platform["rect"])

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

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

Изображения дают богатую детализацию, но требуют внимания к производительности и памяти. Основные шаги:

  1. Загрузить изображение: pygame.image.load(…).convert()/convert_alpha().
  2. Подогнать размер: pygame.transform.scale(img, (screen_width, screen_height)).
  3. В цикле использовать screen.blit(image, rect).

Пример подготовки и масштабирования:

background_images = [
    pygame.image.load("background_0.png").convert(),
    pygame.image.load("background_1.png").convert(),
    pygame.image.load("background_2.png").convert()
]

background_speeds = [1, 2, 3]

for i in range(len(background_images)):
    size = (screen_width, screen_height)
    background_images[i] = pygame.transform.scale(background_images[i], size)

И отрисовка (вместо pygame.draw.rect):

for i in range(len(background_layers)):
    background_layers[i].x -= background_speeds[i]

    if background_layers[i].x <= -screen_width:
        background_layers[i].x = 0

    screen.blit(background_images[i], background_layers[i])

Совет: если фон создаётся из плиток (тайлов), используйте повторяющееся смещение и отрисовывайте столько копий, сколько нужно для покрытия экрана при любом смещении.

Дополнительные функции и идеи

Ниже — набор практических расширений, которые легко интегрировать.

Случайные цвета фонов

Если вам хватает однотонных фонов, можно каждый запуск генерировать случайные RGB-цвета:

import random

background_colors = [
    (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
    (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
    (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
]

Добавление большего числа слоёв

Для богатой сцены добавьте 3–6 слоёв с возрастающими скоростями. Обычно задний план — дробные значения, средний — 1–3, передний — 3 и выше.

Слои с горизонтальной и вертикальной прокруткой

Прокрутку можно комбинировать: задний план медленно движется по Y (плывущие облака), средний — по X (города), передний — по X быстрее (труды в поле зрения).

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

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

  • Используйте convert()/convert_alpha() для подготавливаемых изображений.
  • Масштабируйте изображения один раз при загрузке, а не каждый кадр.
  • Ограничьте количество дорогостоящих операций в главном цикле: математические расчёты хранят в отдельных переменных.
  • Рассмотрите технику dirty rect для частичной перерисовки, если сцена статична.
  • Для мобильных устройств подберите меньшие текстуры и более низкие FPS, если нужно.

Важно: отрисовка большого количества прозрачных изображений (alpha) может сильно замедлить рендер; по возможности предварительно рендерьте композицию слоёв на задний план.

Тестирование и критерии приёмки

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

  • Фон прокручивается плавно без заметных «скачков» при постоянной скорости.
  • Параллакс корректно работает при движении в обе стороны.
  • При смене разрешения экран заполняется корректно (без чёрных полос) или адаптируется выбранной стратегией.
  • Потребление памяти и FPS соответствуют целевым платформам.

Примеры тест-кейсов:

  • Запустить игру на 800×600, 1280×720, 1920×1080 — проверить покрытие экрана.
  • Загрузить высокое разрешение фона на целевом устройстве и замерить FPS под нагрузкой.
  • Проверить, что при достижении границы x <= -screen_width фон «зацикливается» без пропусков.

Чек-лист ролей

Разработчик:

  • Подключил convert() к изображениям
  • Не масштабирует текстуры каждый кадр
  • Ограничил скорость слоя для адекватной читаемости

Художник:

  • Подготовил изображения с запасом по краям (bleed) для безопасной обрезки
  • Предоставил версии под разные соотношения сторон

Тестировщик:

  • Проверил на гориз./вертик. движении
  • Измерил FPS и проверил утечки памяти

Модель принятия решения (flowchart)

Если вы сомневаетесь, использовать ли однотонные слои, тайлы или полноразмерные изображения, следуйте этой упрощённой схеме:

flowchart TD
    A[Нужен фон] --> B{Требуется детализация}
    B -- Низкая --> C[Однотонные слои / градиенты]
    B -- Средняя --> D[Тайловые изображения]
    B -- Высокая --> E[Полноплатные фоновые изображения]
    D --> F{Память / Производительность}
    E --> F
    F -- Ограничена --> G[Уменьшить разрешение / использовать LOD]
    F -- Достаточна --> H[Использовать выбранный подход]

Когда прокрутка даёт сбои (контрпримеры)

  • Фон с незамкнутой текстурой: при простом сбросе x = 0 появится заметный стык.
  • Неверный порядок отрисовки: слои ближе к камере отрисованы раньше — они будут спрятаны за задними.
  • Большое количество полупрозрачных слоёв без предварительного бэка — резкое падение FPS.

Советы по совместимости и миграции

  • Если вы планируете портировать код на другую библиотеку (например, SDL2 напрямую или Godot), держите логику прокрутки отделённой от отрисовки — тогда переезд будет проще.
  • Для Web (через Emscripten/pyodide) используйте маленькие версии текстур и осторожно тестируйте потребление памяти.

Краткий набор полезных сниппетов (cheat sheet)

  • Загрузить и подготовить изображение:
img = pygame.image.load("bg.png").convert()
img = pygame.transform.scale(img, (screen_width, screen_height))
  • Движение слоя с зацикливанием (две копии для корректной отрисовки):
x -= speed
if x <= -screen_width:
    x += screen_width
screen.blit(img, (x, 0))
screen.blit(img, (x + screen_width, 0))
  • Сглаживание движения (delta time):
dt = clock.tick(60) / 1000.0  # секунды
x -= speed * dt

Использование dt позволяет одинаково ощущать скорость на разных частотах кадров.

Риски и способы смягчения

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

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

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

Итог и рекомендации

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

Дополнительная рекомендация: поддерживайте читаемость — слишком быстрый фронтальный слой может мешать восприятию игрового процесса.

Спасибо за чтение — пробуйте, профилируйте и настраивайте под вашу игру.

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

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

Как добавить вершину в Blender
Blender

Как добавить вершину в Blender

Самодельный датчик движения HomeKit на ESP8266
Умный дом

Самодельный датчик движения HomeKit на ESP8266

Как делать заметки по роману в OneNote
Образование

Как делать заметки по роману в OneNote

Что установить на новом ПК — безопасная установка ПО
Программы

Что установить на новом ПК — безопасная установка ПО

Настройки сборки Unity и запуск проекта
Game Development

Настройки сборки Unity и запуск проекта

Управление адресной книгой Amazon
Руководство

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