Параллакс-скроллинг в Arcade (Python)

Зачем нужен параллакс-скроллинг
Параллакс-скроллинг помогает визуально отделить передний план, средний план и фон, делая сцену глубже и интереснее. Коротко:
- Что это: несколько слоёв, двигающихся с разной скоростью.
- Зачем: улучшает восприятие скорости и пространства, добавляет «профессиональную» отделку игре.
- Когда не применять: если игра требует минимальной задержки ввода (например, соревновательные тайм-траблгеймплейные режимы) или на очень слабых устройствах.
Быстрый план (микро-методология)
- Создать класс Layer, у которого есть scroll_speed.
- Заполнить слои спрайтами/изображениями/частицами.
- В update() смещать слои пропорционально движению игрока.
- В on_draw() сначала рисовать фоновые слои, затем платформы и игрока.
- Профилировать и оптимизировать: текстуры, atlases, culling.
Создаём простую игру (исходная структура)
Прежде чем начать, убедитесь, что у вас установлен pip и библиотека Arcade:
pip install arcadeФайл simple-game.py в статье определяет класс Player, наследуемый от arcade.Sprite, и класс Platform для прямоугольных платформ. Класс MyGame отвечает за настройку сцены, создание игрока и платформ, обработку рисования, обновления и ввода.
Ниже — упрощённый пример структуры Layer и настройки слоёв. В оригинале проект доступен в репозитории GitHub и лицензирован MIT.
class Layer(arcade.SpriteList):
def __init__(self, scroll_speed):
super().__init__()
self.scroll_speed = scroll_speed
class MyGame(arcade.Window):
def __init__(self, width, height):
super().__init__(width, height)
arcade.set_background_color(arcade.color.WHITE)
self.player = None
self.platforms = None
self.layers = []
def setup(self):
self.player = Player()
self.platforms = arcade.SpriteList()
gray = arcade.color.GRAY
red = arcade.color.RED
brown = arcade.color.BROWN
yellow = arcade.color.YELLOW
w = SCREEN_WIDTH // 2
h = SCREEN_HEIGHT // 2
self.platforms.append(Platform(w, h - 100, 200, 20, yellow))
self.platforms.append(Platform(w, h + 100, 200, 20, yellow))
layers_data = [
(Layer(0.2), Platform(w, h, 800, 600, gray)),
(Layer(0.5), Platform(w, h - 200, 400, 20, red)),
(Layer(0.5), Platform(w, h + 200, 400, 20, red)),
(Layer(1.0), Platform(w, h - 300, 200, 20, brown)),
(Layer(1.0), Platform(w, h + 300, 200, 20, brown))
]
for layer, platform in layers_data:
layer.append(platform)
self.layers.append(layer)
# Остальные методы: on_draw, update, on_key_press и т.д.Реализация параллакса — ключевые изменения
Чтобы слои двигались по-разному в зависимости от движения игрока, обновляйте координаты спрайтов внутри каждого слоя в методе update. Примерно так выглядит логика:
class MyGame(arcade.Window):
# ...
def on_draw(self):
arcade.start_render()
for layer in self.layers:
layer.draw()
self.platforms.draw()
self.player.draw()
def update(self, delta_time):
self.player.update()
for layer in self.layers:
for sprite in layer:
change = self.player.change_x * layer.scroll_speed
sprite.center_x -= change
# ...Пояснение: self.player.change_x — горизонтальная скорость игрока. Умножая её на layer.scroll_speed, вы получаете смещение для слоя. Слабые (большая глубина) слои должны двигаться медленнее (меньшая scroll_speed), ближние — быстрее.
Регулировка скоростей прокрутки
Экспериментируйте со значениями scroll_speed. Здесь пример, где значения увеличены, чтобы усилить эффект:
class MyGame(arcade.Window):
# ...
def setup(self):
# ...
layers_data = [
(Layer(1.2), Platform(w, h, 800, 600, gray)),
(Layer(2.5), Platform(w, h - 200, 400, 20, red)),
(Layer(3.0), Platform(w, h + 200, 400, 20, red)),
(Layer(4.0), Platform(w, h - 300, 200, 20, brown)),
(Layer(5.0), Platform(w, h + 300, 200, 20, brown))
]
# ...Помните: слишком большие значения могут сделать сцену неестественной. Обычно используют 3–7 слоёв с плавно возрастающими значениями скорости.
Дополнительные эффекты и сочетания
Параллакс легко комбинируется с частицами и погодой. Ниже — пример добавления капли дождя как отдельного набора частиц в фоновой слоях.
class Raindrop(arcade.Sprite):
def __init__(self, x, y):
super().__init__()
self.texture = arcade.make_soft_square_texture(3, blue, outer_alpha=100)
self.center_x = x
self.center_y = y
class BackgroundLayer(arcade.SpriteList):
def __init__(self, scroll_speed):
super().__init__()
self.scroll_speed = scroll_speed
self.raindrops = arcade.SpriteList()
def update(self):
for raindrop in self.raindrops:
raindrop.center_y -= self.scroll_speed * 5
if raindrop.center_y < -10:
raindrop.remove_from_sprite_lists()
def draw(self):
super().draw()
self.raindrops.draw()
class MyGame(arcade.Window):
def __init__(self, width, height):
super().__init__(width, height)
arcade.set_background_color(arcade.color.WHITE)
self.background_layer = BackgroundLayer(0.2)
# ...
def setup(self):
# ...
self.background_layer.raindrops.append(
Raindrop(SCREEN_WIDTH // 2, SCREEN_HEIGHT + 10))
def update(self, delta_time):
self.player.update()
self.background_layer.update()
def on_draw(self):
arcade.start_render()
self.background_layer.draw()
self.platforms.draw()
self.player.draw()Лучшие практики
Планирование слоёв
- Определите роли слоёв: небо, далёкий фон, средний план (архитектура), объекты интерактива, эффекты частиц.
- Внешние большие объекты (например, горы) должны двигаться медленнее.
- Ближние детали — быстрее.
Оптимизация изображений и текстур
- Используйте atlas/атласы спрайтов, где возможно, чтобы уменьшить переключения текстур.
- Сжимайте изображения, но следите за артефактами (PNG для резких краёв, JPEG для фона).
- По возможности используйте поточные текстуры с размером, кратным степени двойки для старых GPU.
Экономьте обработку
- Отбрасывайте (cull) спрайты, которые находятся вне экрана.
- Минимизируйте цикл перебора всех спрайтов на каждом кадре: для больших наборов храните только видимые объекты в отдельном списке.
- Для фоновых неколеблющихся изображений используйте один большой спрайт вместо множества мелких.
Плавность движений
- Используйте интерполяцию и сглаживание (easing), если камера перемещается по ступеням.
- Обрабатывайте фиксированный timestep для физики и независимый для визуальных эффектов.
Отладка и профилирование
- Измеряйте FPS и время, затрачиваемое на обновление и рисование (например, cProfile или встроенные таймеры).
- Временно отключайте слои, чтобы найти узкие места.
- Тестируйте на целевых устройствах (десктоп, ноутбук, слабые ПК, ПК с интегрированной графикой).
Когда параллакс не работает (контрпримеры)
- Когда игровой дизайн требует абсолютной чёткости положения объектов (например, снайперская стрельба) — лишние визуальные слои отвлекают.
- На очень маленьких экранах или при плохой оптимизации параллакс может ухудшить отзывчивость.
- При динамической смене разрешения и неправильной нормализации скоростей слои могут «разъезжаться».
Альтернативные подходы
- Камера (arcade.Camera): вместо смещения каждого слоя смещайте камеру, а фон рендерьте в мировых координатах с поправкой на парраллакс.
- Шейдеры: для продвинутых эффектов используйте фрагментные шейдеры, которые смещают слои с субпиксельной точностью.
- Tilemap: для больших сцен используйте тайлинговые карты с отдельными слоями.
Руководство по тестам и критериям приёмки
Критерии приёмки:
- При движении игрока слои заднего плана смещаются медленнее, ближние — быстрее.
- FPS остаётся стабильным в пределах допустимого для целевой платформы.
- Переходы между зонами (например, телепорт, смена уровня) не приводят к визуальным «прыжкам» слоёв.
- Элементы UI всегда рендерятся поверх сцен.
Тест-кейсы:
- Движение влево/вправо: визуально проверить относительную скорость слоёв.
- Стресс-тест: добавить 1000 спрайтов в дальний фон — проверить падение FPS.
- Мобильный режим: проверить на эмуляторе/устройстве с низкой производительностью.
Чек-листы ролей
Для программиста:
- Реализовать класс Layer с scroll_speed.
- Обновлять позиции слоёв в update().
- Добавить тесты производительности и профилирование.
Для художника/дизайнера:
- Подготовить слои с прозрачностью и корректным выравниванием.
- Предоставить атласы и оптимизированные текстуры.
Для тестировщика:
- Пройти тест-кейсы (см. выше).
- Проверить на целевых конфигурациях.
Ментальные модели и эвристики
- Правило трёх расстояний: передний план / средний план / фон — минимум три слоя для узнаваемого параллакса.
- Малые смещения для дальних объектов, большие — для ближних.
- Чем выше детализация объекта, тем ближе он должен «чувствоваться” к камере.
Совместимость и миграция
- Arcade 2.x может менять API рендеринга; проверяйте совместимость методов SpriteList и Camera при обновлении библиотеки.
- При миграции на OpenGL/GLSL-решение сохраняйте концепцию слоёв, но переносите логику смещения в шейдер.
Краткое резюме
Параллакс-скроллинг — простой и эффективный способ добавить глубину в 2D-игры. Начните с 3–5 слоёв, отлаживайте скорости и профиль производительности, а затем расширяйте эффект частицами и погодой.
Часто задаваемые вопросы
Нужно ли использовать равное количество объектов в каждом слое?
Нет. Главное — визуальная гармония. Дальний фон обычно содержит меньше интерактивных объектов, но больше крупных графических элементов.
Как перевести сцену на камеры вместо смещения каждого спрайта?
Можно использовать arcade.Camera: рендерьте фоны с поправкой на позицию камеры и множитель параллакса. Это уменьшит перебиратья спрайтов, но потребует расчёта мировых координат для каждого слоя.
Какие форматы изображений лучше использовать?
Для фона с плавными градиентами — JPEG (меньше вес), для слоёв с прозрачностью и резкими краями — PNG.
Похожие материалы
Как сделать кроссоверный Ethernet‑кабель
Как вести заметки в Notion — практические приёмы
Отключить Popular Highlights на Kindle
Авторское право на YouTube: что такое strike
Пропуск звонков через «Не беспокоить» на iPhone