О чем этот пример
Эффект свечения (bloom) — классический приём в графике, который добавляет реалистичности и атмосферности игровым сценам. Раньше его реализация требовала сложных шейдеров, но в Phaser 3.70 появилась удобная система параллельных фильтров. В этой статье мы разберём, как создать динамический эффект bloom для логотипа, используя встроенные API Phaser, и как управлять им с помощью твинов для создания плавной анимации.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
image;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('phaser-logo', 'assets/sprites/phaser3-logo-x2.png');
}
create ()
{
const image = this.add.image(640, 360, 'phaser-logo');
const text = this.add.text(640, 500, 'Bloom with Parallel Filters', { font: '32px Arial', fill: '#88ffff' }).setOrigin(0.5);
const parallelFilters = this.cameras.main.filters.internal.addParallelFilters();
parallelFilters.top.addThreshold(0.5, 1);
parallelFilters.top.addBlur();
parallelFilters.blend.blendMode = Phaser.BlendModes.ADD;
parallelFilters.blend.amount = 0;
// Alternatively, instead of creating parallelFilters,
// use Actions.AddEffectBloom:
// const { parallelFilters } = Phaser.Actions.AddEffectBloom(this.cameras.main, { blendAmount: 0 });
this.tweens.add({
targets: parallelFilters.blend,
amount: 2,
duration: 1000,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
});
}
}
const config = {
type: Phaser.WEBGL,
width: 1280,
height: 720,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Настройка сцены и загрузка ассетов
Всё начинается с базовой структуры класса сцены Example. В методе preload() мы устанавливаем базовый URL для загрузки и загружаем изображение логотипа Phaser. Это стандартный подход для подготовки ресурсов.
class Example extends Phaser.Scene
{
image;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('phaser-logo', 'assets/sprites/phaser3-logo-x2.png');
}
Создание объектов и параллельных фильтров
В методе create() мы размещаем изображение и текст на сцене. Затем происходит самое интересное — создание группы параллельных фильтров для основной камеры. Мы получаем доступ к внутренней системе фильтров камеры через this.cameras.main.filters.internal и вызываем метод addParallelFilters(). Этот метод возвращает объект, который позволяет работать с несколькими графическими эффектами одновременно.
create ()
{
const image = this.add.image(640, 360, 'phaser-logo');
const text = this.add.text(640, 500, 'Bloom with Parallel Filters', { font: '32px Arial', fill: '#88ffff' }).setOrigin(0.5);
const parallelFilters = this.cameras.main.filters.internal.addParallelFilters();
Далее мы настраиваем полученный объект parallelFilters. У него есть свойство top, представляющее собой цепочку фильтров. Мы добавляем в неё два фильтра: сначала addThreshold(0.5, 1), который отсекает все пиксели с яркостью ниже 0.5 (оставляя только яркие участки), а затем addBlur(), который размывает полученную маску. Свойство blend отвечает за смешивание результата с исходным изображением. Мы устанавливаем ему режим наложения Phaser.BlendModes.ADD (сложение цветов) и начальную интенсивность (amount) в 0.
parallelFilters.top.addThreshold(0.5, 1);
parallelFilters.top.addBlur();
parallelFilters.blend.blendMode = Phaser.BlendModes.ADD;
parallelFilters.blend.amount = 0;
Альтернативный способ: использование Actions.AddEffectBloom
Phaser предоставляет упрощённый способ создания этого же эффекта через Phaser.Actions.AddEffectBloom. Этот статический метод делает всю ручную настройку за вас. В примере он закомментирован, но вы можете использовать его для быстрого прототипирования.
// Alternatively, instead of creating parallelFilters,
// use Actions.AddEffectBloom:
// const { parallelFilters } = Phaser.Actions.AddEffectBloom(this.cameras.main, { blendAmount: 0 });
Метод принимает камеру и объект с настройками (например, blendAmount) и возвращает тот же объект parallelFilters, что и при ручном создании. Это удобно, когда нужен стандартный bloom без тонкой настройки каждого этапа.
Анимация эффекта с помощью твинов
Чтобы эффект не был статичным, мы анимируем интенсивность наложения (смешивания) с помощью системы твинов Phaser. Мы создаём твин, который нацелен на свойство amount объекта parallelFilters.blend.
this.tweens.add({
targets: parallelFilters.blend,
amount: 2,
duration: 1000,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
});
Параметры твина:
- targets: объект, чьё свойство будет анимировано.
- amount: целевое значение интенсивности (от 0 до 2).
- duration: длительность анимации в миллисекундах (1000 мс = 1 секунда).
- yoyo: если true, анимация будет проигрываться в обратном порядке после завершения.
- repeat: -1: бесконечное повторение анимации.
- ease: функция плавности 'Sine.easeInOut' для создания мягкого ускорения и замедления.
В результате интенсивность свечения плавно нарастает от 0 до 2 и обратно, создавая пульсирующий эффект.
Конфигурация и запуск игры
В конце кода определяется стандартная конфигурация игры config. Обратите внимание, что для работы фильтров необходим рендерер Phaser.WEBGL. Мы указываем размеры холста, ID родительского элемента и класс сцены. Затем создаётся экземпляр игры new Phaser.Game(config).
const config = {
type: Phaser.WEBGL,
width: 1280,
height: 720,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Параллельные фильтры в Phaser открывают мощный и относительно простой путь для создания пост-обработки прямо в основном цикле рендеринга камеры. Вы научились создавать эффект bloom вручную, настраивая порог яркости, размытие и режим смешивания, а также анимировать его. Для экспериментов попробуйте изменить значение в addThreshold (например, на 0.8), чтобы свечение затрагивало только самые яркие участки. Используйте другие режимы наложения из Phaser.BlendModes, такие как SCREEN или MULTIPLY, для разных визуальных стилей. Также поэкспериментируйте с добавлением других фильтров в цепочку parallelFilters.top, например, addColorMatrix() для тонирования свечения.
