О чем этот пример
Фильтры в Phaser 3 — это мощный инструмент для постобработки графики, позволяющий применять к спрайтам и другим объектам различные визуальные эффекты, такие как размытие, свечение или пикселизация. Умение управлять ими в реальном времени открывает двери к созданию динамичных визуальных переходов, эффектов повреждения или стилизованного вида игры. В этой статье мы разберем конкретный пример, который показывает, как добавить фильтр пикселизации к изображению и изменять его силу с клавиатуры. Вы научитесь создавать, настраивать и интерактивно модифицировать фильтры, что является фундаментальным навыком для визуального программирования в 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.image('pic', 'assets/pics/neotokyo-ai.jpg');
}
create ()
{
const sprite = this.add.image(400, 300, 'pic');
const fx = sprite.enableFilters().filters.internal.addPixelate(-1);
this.add.text(10, 10, '[W] Increase Pixelate\n[S] Decrease Pixelate').setResolution(window.devicePixelRatio).setShadow(2, 2);
const amount = this.add.text(790, 10, 'FX.amount: -1').setResolution(window.devicePixelRatio).setOrigin(1, 0).setShadow(2, 2);
this.input.keyboard.on('keydown-W', () => {
fx.amount++;
amount.setText(`FX.amount: ${fx.amount}`);
});
this.input.keyboard.on('keydown-S', () => {
if (fx.amount > -1)
{
fx.amount--;
amount.setText(`FX.amount: ${fx.amount}`);
}
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
Вся логика примера размещена внутри класса сцены, унаследованного от Phaser.Scene. Метод preload отвечает за загрузку ресурсов.
Здесь используется this.load.setBaseURL() для указания базового URL, от которого будут загружаться все последующие ресурсы. Это удобно, когда все ассеты лежат в одной директории на удаленном сервере. Затем загружается одно изображение с ключом 'pic'.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('pic', 'assets/pics/neotokyo-ai.jpg');
}
Создание спрайта и добавление фильтра
В методе create происходит основная инициализация. Сначала изображение добавляется на сцену как спрайт с помощью this.add.image().
Ключевой момент — применение фильтра. Метод sprite.enableFilters() активирует систему фильтров для данного спрайта и возвращает объект filters. Далее мы обращаемся к его внутреннему списку (internal) и добавляем новый фильтр пикселизации с помощью метода addPixelate(). Аргумент -1 задает начальное значение силы эффекта.
const sprite = this.add.image(400, 300, 'pic');
const fx = sprite.enableFilters().filters.internal.addPixelate(-1);
Добавление текстовых подсказок
Для интерактивности на сцену добавляются два текстовых объекта. Первый (this.add.text(10, 10, ...)) служит инструкцией для пользователя, показывая, какие клавиши использовать.
Второй текстовый объект (amount) динамически отображает текущее значение свойства amount фильтра. Он позиционируется в правом верхнем углу сцены с помощью метода .setOrigin(1, 0), что выравнивает его по правому краю. Методы .setResolution() и .setShadow() улучшают читаемость текста на экранах с высоким DPI и добавляют тень соответственно.
this.add.text(10, 10, '[W] Increase Pixelate\n[S] Decrease Pixelate').setResolution(window.devicePixelRatio).setShadow(2, 2);
const amount = this.add.text(790, 10, 'FX.amount: -1').setResolution(window.devicePixelRatio).setOrigin(1, 0).setShadow(2, 2);
Обработка ввода и динамическое изменение фильтра
Интерактивность реализуется через слушатели событий клавиатуры this.input.keyboard.on. При нажатии клавиши `Wзначениеfx.amountувеличивается на единицу, а при нажатииS— уменьшается, но только если оно больше-1`. Это предотвращает уход значения в бесконечную отрицательную область, что может привести к неожиданному визуальному результату.
После каждого изменения свойства amount фильтра автоматически перерисовывается, и эффект на изображении меняется. Текстовый объект amount также обновляется, чтобы отразить новое значение.
this.input.keyboard.on('keydown-W', () => {
fx.amount++;
amount.setText(`FX.amount: ${fx.amount}`);
});
this.input.keyboard.on('keydown-S', () => {
if (fx.amount > -1)
{
fx.amount--;
amount.setText(`FX.amount: ${fx.amount}`);
}
});
Конфигурация и запуск игры
За пределами класса сцены определяется объект конфигурации config. В нем задаются основные параметры игры: тип рендерера (Phaser.AUTO), размеры холста, цвет фона и родительский HTML-элемент. Важнейшее поле — scene, куда передается наш класс Example.
Инициализация игры происходит через создание экземпляра Phaser.Game с этой конфигурацией. На этом этапе Phaser создает холст, системы ввода, физики и запускает жизненный цикл сцены.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Этот пример наглядно демонстрирует простоту и мощь системы фильтров Phaser 3. Вы можете не только применять статические эффекты, но и динамически управлять их параметрами, создавая живую, реагирующую на действия игрока графику.
Для экспериментов попробуйте:
1. Привязать изменение fx.amount не к клавишам, а к положению мыши или времени.
2. Применить другие фильтры из коллекции filters.internal, например, add.Blur или add.Glow.
3. Комбинировать несколько фильтров на одном спрайте, чтобы создать уникальные визуальные стили.
