О чем этот пример
Создание динамичных визуальных эффектов — ключевая часть геймдева. В Phaser 3 частицы (Particle Emitter) позволяют легко реализовать дождь, огонь, магию и другие системы. Однако стандартный эмиттер непрерывно испускает частицы. В этой статье мы разберем, как с помощью свойства `hold` сделать так, чтобы частицы появлялись, замирали на месте на заданное время и лишь затем начинали двигаться по законам физики. Этот прием отлично подходит для создания эффекта "взведенной" катапульты, застывших во времени сфер или подготовки каскадного падения объектов.
Версия 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.image('bg', 'assets/skies/gradient26.png');
this.load.image('ball', 'assets/demoscene/green_ball.png');
this.load.image('platform', 'assets/particles/platform.png');
}
create ()
{
this.add.image(400, 300, 'bg');
this.add.image(-100, 500, 'platform').setOrigin(0, 0);
this.add.image(412, 500, 'platform').setOrigin(0, 0);
this.add.particles(0, -32, 'ball', {
x: { min: 0, max: 800 },
gravityY: 200,
lifespan: 2235,
hold: 2000,
sortProperty: 'lifeT',
sortOrderAsc: true
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Суть свойства `hold`
Свойство hold в конфигурации эмиттера частиц — это время в миллисекундах, в течение которого только что созданная частица будет находиться в состоянии покоя. Она появится на экране с заданными начальными координатами, но не будет подвержена силам (таким как гравитация gravityY) и не начнет "стареть" (уменьшаться lifespan).
По истечении времени hold частица "оживает": к ней применяется физика, и запускается отсчет ее времени жизни. Это позволяет создавать сложные, многоступенчатые эффекты и контролировать момент начала движения.
Разбор примера: Застывший дождь из шаров
В исходном коде создается простая сцена с фоном, двумя платформами и одним эмиттером частиц. Давайте посмотрим на его конфигурацию.
this.add.particles(0, -32, 'ball', {
x: { min: 0, max: 800 },
gravityY: 200,
lifespan: 2235,
hold: 2000,
sortProperty: 'lifeT',
sortOrderAsc: true
});
Здесь ключевые параметры:
- `x: Частицы будут появляться случайным образом по всей ширине экрана (от 0 до 800 пикселей). Их начальная координатаy` фиксирована и равна -32 (чуть выше верхней границы окна).
- gravityY: Сила гравитации, которая начнет действовать на частицу только после фазы hold.
- lifespan: Общее время жизни частицы (2235 мс), которое также отсчитывается после окончания hold.
- hold: Время "заморозки" — 2000 миллисекунд (2 секунды).
Как работает жизненный цикл частицы
Благодаря hold жизненный цикл каждой частицы делится на две четкие фазы.
**Фаза 1: Ожидание (0-2000 мс)**
Частица появляется вверху экрана и неподвижно висит в воздухе. Гравитация и отсчет lifespan приостановлены. За первые 2 секунды эмиттер успевает создать множество таких "замерзших" шаров, равномерно заполняя пространство над платформами.
**Фаза 2: Падение (2000-4235 мс)**
Ровно через 2000 мс после создания частица "просыпается". С этого момента:
1. На нее начинает действовать gravityY: 200, и шар устремляется вниз.
2. Запускается таймер lifespan. Через 2235 мс после начала этой фазы частица автоматически уничтожится.
Эффект: сначала на экране формируется "облако" из статичных зеленых шаров, а затем они все одновременно начинают падать каскадом.
Сортировка для визуальной целостности
В конфиге также присутствуют параметры sortProperty и sortOrderAsc. Они управляют порядком отрисовки (рендеринга) частиц.
sortProperty: 'lifeT',
sortOrderAsc: true
lifeT — это внутреннее свойство частицы, представляющее ее оставшееся время жизни. При sortOrderAsc: true частицы с меньшим оставшимся временем жизни (т.е. те, что "старше") будут отрисованы первыми, а более новые — поверх них.
В нашем примере, так как все частицы начинают жить одновременно после hold, сортировка по lifeT обеспечивает стабильный порядок отрисовки, предотвращая мерцание и визуальные артефакты, когда шары перекрывают друг друга во время падения.
Практическое применение и вариации
Свойство hold открывает путь к нестандартным игровым механикам и эффектам.
**Идеи для использования:**
1. **Подготовка атаки:** Вражеская башня "заряжается" (частицы копятся), а затем выпускает залп.
2. **Эффект замедления времени:** Активация способности замораживает все летящие снаряды (hold: 3000), а после отмены способности они продолжают полет.
3. **Создание сложных форм:** Можно расположить эмиттер так, чтобы частицы образовали статичную надпись или логотип, а затем "рассыпались".
**Пример: Эмиттер с наклонным разбросом**
this.add.particles(400, 300, 'spark', {
speed: { min: 100, max: 200 },
angle: { min: 0, max: 180 },
lifespan: 1500,
hold: 1000,
scale: { start: 1, end: 0 },
emitting: false // Выпускаем одну порцию
});
emitter.explode(50); // Создаем 50 частиц сразу
В этом коде 50 искр появятся в форме полукруга, застынут на 1 секунду, а затем разлетятся с разной скоростью, постепенно исчезая.
Что попробовать дальше
Свойство hold в эмиттере частиц Phaser 3 — это мощный инструмент для разделения момента появления объекта и начала его физической симуляции. Оно добавляет контролируемую задержку, которая полезна для создания драматических пауз, эффектов накопления и сложной хореографии движения множества объектов.
**Экспериментируйте:** Попробуйте комбинировать hold с другими свойствами, такими как delay (задержка между испусканием частиц) или frequency. Измените пример, добавив свойство onHold (если оно доступно в вашей версии Phaser) для вызова функции в момент "пробуждения" каждой частицы. Это может стать основой для интерактивных головоломок или зрелищных босс-файтов.
