О чем этот пример
Частицы в играх — это не только точки или простые формы. С помощью Phaser вы можете создавать эффектные системы частиц, где каждая частица — полноценный анимированный спрайт, взятый из атласа. Это открывает двери для создания сложных визуальных эффектов, таких как магические вспышки из самоцветов, падающие анимированные листья или искры с собственной анимацией. В этой статье мы разберем пример, где частицы эммитера используют готовые анимации из атласа и плавно движутся по сцене. Вы научитесь создавать анимации из кадров атласа, настраивать эммитер для работы с ними и динамически управлять его позицией с помощью твинов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.55.2.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
}
create ()
{
this.anims.create({ key: 'diamond', frames: this.anims.generateFrameNames('gems', { prefix: 'diamond_', end: 15, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'prism', frames: this.anims.generateFrameNames('gems', { prefix: 'prism_', end: 6, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'ruby', frames: this.anims.generateFrameNames('gems', { prefix: 'ruby_', end: 6, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'square', frames: this.anims.generateFrameNames('gems', { prefix: 'square_', end: 14, zeroPad: 4 }), repeat: -1 });
const particles = this.add.particles('gems');
const emitter = particles.createEmitter({
anim: [ 'diamond', 'prism', 'square', 'ruby' ],
x: 100,
y: 100,
speed: 100,
lifespan: 6000,
scale: { start: 0.3, end: 1 },
gravityY: 80
});
this.tweens.add({
targets: emitter,
x: 700,
yoyo: true,
repeat: -1,
duration: 2000,
ease: 'sine.inout'
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка и подготовка анимаций
Перед созданием эммитера необходимо загрузить атлас спрайтов и создать из его кадров анимации. В методе preload используется this.load.atlas, который загружает изображение и JSON-файл с данными о кадрах.
Далее, в create, с помощью this.anims.create создаются четыре анимации. Ключевой метод this.anims.generateFrameNames автоматически генерирует имена кадров на основе префикса и диапазона, что удобно при регулярной нумерации кадров в атласе. Параметр zeroPad: 4 гарантирует, что номера кадров будут дополнены нулями до четырех символов (например, 'diamond_0015').
this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
this.anims.create({ key: 'diamond', frames: this.anims.generateFrameNames('gems', { prefix: 'diamond_', end: 15, zeroPad: 4 }), repeat: -1 });
Создание системы частиц и эммитера
Система частиц создается как игровой объект через this.add.particles. В конструктор передается ключ текстуры (или атласа), которую будут использовать частицы. В данном случае это 'gems'.
Затем создается непосредственно эммитер — источник частиц. Важнейший параметр здесь — anim. Вместо текстуры (frame) мы указываем массив ключей анимаций. Phaser будет случайным образом выбирать одну из этих анимаций для каждой новой частицы. Остальные параметры задают базовое поведение: стартовую позицию, начальную скорость, время жизни частицы, изменение масштаба от маленького к большому и гравитацию по оси Y.
const particles = this.add.particles('gems');
const emitter = particles.createEmitter({
anim: [ 'diamond', 'prism', 'square', 'ruby' ],
x: 100,
y: 100,
speed: 100,
lifespan: 6000,
scale: { start: 0.3, end: 1 },
gravityY: 80
});
Динамическое движение эммитера с помощью твинов
Чтобы эммитер не был статичным, его можно анимировать как любой другой объект. В примере используется this.tweens.add. Целью (targets) твина является сам объект emitter.
Твин плавно меняет свойство `xэммитера от исходного значения (100) до 700 пикселей за 2 секунды (duration). Параметрyoyo: trueзаставляет анимацию проигрываться в обратном порядке после завершения, аrepeat: -1делает ее бесконечно повторяющейся. Функция плавностиsine.inout` обеспечивает плавное ускорение и замедление движения.
this.tweens.add({
targets: emitter,
x: 700,
yoyo: true,
repeat: -1,
duration: 2000,
ease: 'sine.inout'
});
Ключевые параметры эммитера и их влияние
Поведение потока частиц тонко настраивается параметрами эммитера.
* speed: Определяет начальную скорость разлета частиц во всех направлениях.
* lifespan: Время в миллисекундах, в течение которого частица существует от момента создания до исчезновения. Большое значение (6000 мс = 6 сек) позволяет частицам проделать длинный путь и плавно исчезнуть.
* scale: Объект с start и end позволяет задать интерполяцию масштаба частицы от начала и до конца жизни. Здесь частицы увеличиваются с 30% до 100% своего размера.
* gravityY: Постоянное ускорение, применяемое к частицам по оси Y. Положительное значение (80) притягивает их вниз, создавая эффект падения под действием силы тяжести, несмотря на начальный разлет.
Комбинация этих параметров создает эффект фонтана из самоцветов, которые разлетаются, затем падают вниз, постепенно увеличиваясь в размерах.
Что попробовать дальше
Использование анимированных спрайтов в качестве частиц — мощный прием для обогащения визуальной составляющей игры. Вы можете применять этот подход для создания огня из анимированных языков пламени, дождя из капель с рябью, следов из вращающихся пылинок.
Для экспериментов попробуйте:
1. Изменить параметры gravityY, speed и lifespan, чтобы получить совершенно разные траектории — от хаотичного взрыва до медленного водопада.
2. Добавить твин для изменения свойства gravityY самого эммитера во времени, чтобы сила притяжения плавно менялась.
3. Использовать спрайт-лист вместо атласа и создать анимацию на его основе для частиц.
4. Связать положение эммитера с курсором мыши (this.input.mousePointer), чтобы поток самоцветов следовал за игроком.
