О чем этот пример
Добавление ощущения глубины и скорости — ключевой элемент в визуальном оформлении игр. Один из самых эффектных способов достичь этого — использовать параллакс-эффект. В этой статье мы разберём, как создать сложный многослойный параллакс, используя всего один эмиттер частиц Phaser. Вы научитесь управлять слоями, скоростью и частотой появления объектов, что позволит вам оживить фон вашей игры, будь то звёздное поле, падающие листья или стремительный полёт в туннеле.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('megaset', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');
}
create ()
{
const offscreen = new Phaser.Geom.Rectangle(-400, 0, 400, 600);
const screen = new Phaser.Geom.Rectangle(-400, 0, 1200, 600);
this.add.particles('megaset', [
{
frame: 'blue_ball',
emitZone: { source: offscreen },
deathZone: { source: screen, type: 'onLeave' },
frequency: 100,
speedX: { min: 80, max: 120 },
lifespan: 30000,
scale: 0.5
},
{
frame: 'red_ball',
emitZone: { source: offscreen },
deathZone: { source: screen, type: 'onLeave' },
frequency: 150,
speedX: { min: 180, max: 220 },
lifespan: 30000,
scale: 0.8
},
{
frame: 'yellow_ball',
emitZone: { source: offscreen },
deathZone: { source: screen, type: 'onLeave' },
frequency: 500,
quantity: 4,
speedX: { min: 280, max: 320 },
lifespan: 30000
}
]);
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Суть примера: один эмиттер — три слоя
Ключевая идея этого примера — создание иллюзии трёх отдельных слоёв движения (параллакса) с помощью одного контейнера частиц ParticleEmitterManager. Вместо того чтобы создавать три независимых эмиттера, мы передаём в метод this.add.particles() массив из трёх конфигурационных объектов. Каждый объект описывает свой слой частиц с уникальными свойствами: текстурой (frame), скоростью (speedX) и частотой появления (frequency).
Частицы рождаются за пределами видимой области и уничтожаются, покидая заданную зону. Это создаёт бесконечный, управляемый поток.
Геометрия: зоны рождения и смерти
Контроль над жизненным циклом частиц осуществляется через геометрические зоны Phaser.Geom.Rectangle. В примере определены две зоны:
* offscreen: Зона эмиссии (рождения). Это прямоугольник шириной 400 пикселей, расположенный **слева** от левой границы экрана (x: -400). Все частицы начинают свой путь именно здесь.
* screen: Зона смерти. Это более широкий прямоугольник (1200 пикселей), который начинается там же, где и offscreen, но заканчивается далеко **справа** от экрана. Частицы будут уничтожены, как только покинут эту зону (type: 'onLeave').
const offscreen = new Phaser.Geom.Rectangle(-400, 0, 400, 600);
const screen = new Phaser.Geom.Rectangle(-400, 0, 1200, 600);
Такая настройка гарантирует, что частицы плавно появляются с левого края и исчезают, улетев далеко за правый, не создавая резких "обрезаний".
Настройка слоёв частиц
Сердце примера — массив конфигов для слоёв. Давайте разберём свойства каждого:
1. **Слой 1 (Синие шары):** Медленный, дальний фон.
* frame: 'blue_ball' — использует синий спрайт из атласа.
* speedX: { min: 80, max: 120 } — самая низкая скорость.
* frequency: 100 — появляется реже других (раз в 100 мс).
* scale: 0.5 — уменьшенный размер, усиливает ощущение удалённости.
2. **Слой 2 (Красные шары):** Средний слой.
* frame: 'red_ball'.
* speedX: { min: 180, max: 220 } — скорость выше.
* frequency: 150 — появляется чаще синих.
* scale: 0.8 — размер больше, чем у дальнего слоя.
3. **Слой 3 (Жёлтые шары):** Быстрый, ближний слой.
* frame: 'yellow_ball'.
* speedX: { min: 280, max: 320 } — максимальная скорость.
* frequency: 500 и quantity: 4 — самая высокая частота, и за один раз создаётся сразу 4 частицы, создавая плотный поток.
this.add.particles('megaset', [
{
frame: 'blue_ball',
emitZone: { source: offscreen },
deathZone: { source: screen, type: 'onLeave' },
frequency: 100,
speedX: { min: 80, max: 120 },
lifespan: 30000,
scale: 0.5
},
// ... остальные конфиги
]);
Общие для всех свойства emitZone, deathZone и большой lifespan (30000 мс) обеспечивают общую логику движения и долгую "жизнь" частиц, если они не покинули зону смерти раньше.
Практическое применение и адаптация
Этот паттерн не ограничивается шарами. Подставив другие кадры из атласа или отдельные изображения, вы можете создать:
* **Звёздное поле:** Замените шары на спрайты звёзд разного размера и свечения.
* **Лес или город:** Используйте спрайты деревьев или зданий, изменив speedX на speedY для вертикального параллакса (например, при подъёме в гору).
* **Эффект скорости:** В гоночной игре такие слои могут изображать блики на обочине или туннеле.
Важно помнить, что frequency и quantity влияют на общую производительность. Для очень плотных или быстрых слоев можно увеличить speedX и уменьшить frequency, чтобы сохранить количество частиц на экране, но снизить нагрузку от их создания.
Что попробовать дальше
Использование одного эмиттера с массивом конфигураций — это мощный и производительный подход к созданию сложных визуальных эффектов с параллаксом. Вы получаете единую систему управления для всех слоёв. Для экспериментов попробуйте изменить форму зон (Phaser.Geom.Circle или Phaser.Geom.Line), добавить гравитацию (gravityY), случайное вращение (rotate) или изменить цвет частиц (tint) со временем. Это откроет путь к созданию по-настоящему уникальных атмосферных эффектов в вашей игре.
