О чем этот пример
Визуальные эффекты (фильтры) — мощный инструмент для создания атмосферы и фокусировки внимания игрока. В этом примере мы рассмотрим, как добавить интерактивное виньетирование к изображению, которое можно перемещать мышью и изменять его радиус колёсиком. Это не просто декоративный приём, а способ управлять взглядом пользователя, создавая эффекты старых фотографий, подзорной трубы или просто затемняя края экрана для драматического эффекта.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('pic', 'assets/pics/anime-arcade-ai.jpg');
}
create ()
{
const sprite = this.add.image(400, 300, 'pic');
this.add.text(10, 10, 'Mouse to move vignette. Mouse wheel to adjust radius');
const fx = sprite.enableFilters().filters.internal.addVignette();
fx.radius = 0.3;
fx.strength = 0.425;
fx.color.setTo(0, 0, 0, 0); // Vignette alpha.
sprite.setInteractive();
sprite.on('pointermove', (pointer, x, y) => {
fx.x = x / 512;
fx.y = y / 512;
});
sprite.on('wheel', (pointer, x, y) => {
fx.radius += y * -0.001;
fx.radius = Phaser.Math.Clamp(fx.radius, 0, 1);
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#0a0067',
parent: 'phaser-example',
scene: Example
};
let game = new Phaser.Game(config);
Загрузка ресурсов и создание спрайта
Всё начинается в методе preload, где мы загружаем фоновое изображение. В create это изображение размещается в центре сцены как обычный спрайт.
const sprite = this.add.image(400, 300, 'pic');
Важный момент: для работы с фильтрами спрайт должен быть особым типом — Image (или Sprite) с поддержкой WebGL. Обычный this.add.image подходит. Далее мы добавляем текстовую подсказку для пользователя.
Включение фильтров и добавление виньетки
Чтобы применить фильтр, спрайту нужно включить их поддержку. Метод .enableFilters() активирует систему фильтров для этого объекта и возвращает менеджер фильтров. Через свойство .filters.internal мы получаем доступ к внутренней системе и добавляем эффект виньетки.
const fx = sprite.enableFilters().filters.internal.addVignette();
Переменная fx теперь хранит экземпляр фильтра Vignette, через который мы управляем его параметрами. Сразу зададим базовые настройки: радиус, силу и цвет. Обратите внимание, что цвет задаётся как RGBA, и мы устанавливаем альфа-канал в 0, оставляя цвет чёрным, но полностью прозрачным — сама виньетка создаётся алгоритмически.
fx.radius = 0.3;
fx.strength = 0.425;
fx.color.setTo(0, 0, 0, 0);
Интерактивность: перемещение виньетки
Делаем спрайт интерактивным, чтобы он реагировал на события мыши. Затем вешаем обработчик на событие pointermove.
sprite.setInteractive();
sprite.on('pointermove', (pointer, x, y) => {
fx.x = x / 512;
fx.y = y / 512;
});
Координаты `xиyв колбэке — это локальные координаты указателя относительно спрайта. Свойства фильтраfx.xиfx.y` ожидают нормализованные значения (от 0 до 1), где (0,0) — это левый верхний угол спрайта, а (1,1) — правый нижний. Поэтому мы делим координаты на 512 (предполагаемая ширина текстуры/изображения). В вашем случае это значение может быть другим, его стоит подбирать эмпирически или вычислять на основе размера спрайта.
Интерактивность: изменение радиуса
Для изменения радиуса виньетки используем событие wheel. Свойство `y` в объекте события содержит величину прокрутки.
sprite.on('wheel', (pointer, x, y) => {
fx.radius += y * -0.001;
fx.radius = Phaser.Math.Clamp(fx.radius, 0, 1);
});
Мы изменяем fx.radius на величину прокрутки, умноженную на -0.001 (инверсия знака и коэффициент для плавности). Затем обязательно ограничиваем значение функцией Phaser.Math.Clamp между 0 и 1, так как радиус — это нормализованный параметр.
Что попробовать дальше
Вы только что реализовали динамический виньеточный фильтр, управляемый пользователем. Этот приём можно использовать для создания мини-игр с фонариком в тёмной комнате, эффекта туннельного зрения или просто как часть фоторедактора в игре. Поэкспериментируйте: привяжите силу виньетки fx.strength к геймпаду, измените fx.color на красный для эффекта ранения или анимируйте параметры со временем для плавного появления затемнения.
