О чем этот пример
Современные игры часто используют визуальные эффекты для привлечения внимания к ключевым областям экрана и создания атмосферы. В этой статье мы рассмотрим, как легко добавить динамическое виньетирование в Phaser 3 с помощью встроенного API внешних фильтров камеры. Вы научитесь создавать эффект затемнения краёв изображения, анимировать его силу и менять цвет. Этот приём особенно полезен для кат-сцен, диалоговых окон или для визуального выделения важных объектов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
image;
vignette;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('anime-market', 'assets/pics/anime-market.png');
}
create ()
{
this.image = this.add.image(400, 300, 'anime-market').setScale(2);
this.vignette = this.cameras.main.filters.external.addVignette(0.5, 0.37, 1, 0.25);
this.vignette.color.setTo(127, 255, 255);
}
update (time, delta)
{
this.image.x = 16 * Math.sin(time / 765) + 640;
this.image.y = 16 * Math.sin(time / 1000) + 512;
this.image.rotation = 0.005 * Math.sin(time / 881);
this.vignette.strength = 0.1 + 0.05 * Math.sin(time / 384);
}
}
const config = {
type: Phaser.AUTO,
width: 1280,
height: 720,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
let game = new Phaser.Game(config);
Инициализация сцены и загрузка изображения
В Phaser вся игровая логика организуется в сценах. В данном примере мы создаём класс Example, который наследуется от Phaser.Scene. Метод preload() используется для предварительной загрузки ресурсов. Здесь мы загружаем одно фоновое изображение.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('anime-market', 'assets/pics/anime-market.png');
}
Метод setBaseURL() задаёт базовый путь для загрузчика, а load.image() регистрирует изображение с ключом 'anime-market'.
Создание изображения и добавление фильтра виньетирования
В методе create(), который вызывается один раз после загрузки ресурсов, мы размещаем изображение на сцене и применяем к основной камере фильтр виньетирования. Изображение масштабируется, чтобы заполнить большую часть экрана.
create ()
{
this.image = this.add.image(400, 300, 'anime-market').setScale(2);
this.vignette = this.cameras.main.filters.external.addVignette(0.5, 0.37, 1, 0.25);
this.vignette.color.setTo(127, 255, 255);
}
Ключевой момент — обращение к менеджеру внешних фильтров основной камеры через this.cameras.main.filters.external. Метод addVignette() создаёт и добавляет фильтр, принимая параметры: `x(горизонтальный центр),y(вертикальный центр),radius(радиус внутренней, не затемнённой области) иstrength(сила затемнения). Возвращённый объект фильтра сохраняется в свойствеthis.vignetteдля дальнейшего управления. Сразу же меняем цвет виньетирования с помощьюthis.vignette.color.setTo()`. По умолчанию цвет чёрный, здесь же задаётся светло-голубой оттенок.
Анимация изображения и силы виньетирования
Метод update() вызывается на каждом кадре игры. В нём мы анимируем положение, поворот фонового изображения и силу эффекта виньетирования, создавая живое, дышащее движение.
update (time, delta)
{
this.image.x = 16 * Math.sin(time / 765) + 640;
this.image.y = 16 * Math.sin(time / 1000) + 512;
this.image.rotation = 0.005 * Math.sin(time / 881);
this.vignette.strength = 0.1 + 0.05 * Math.sin(time / 384);
}
Параметр time — это время в миллисекундах с момента старта игры. Используя функцию Math.sin(), мы получаем плавные колебания. Координаты `xиyизображения, а также егоrotation(вращение) меняются по синусоидальному закону с разной частотой, что делает движение менее механическим. Сила виньетированияthis.vignette.strength` также пульсирует, периодически усиливая и ослабляя эффект. Это свойство доступно для изменения после создания фильтра.
Конфигурация игры
Для запуска игры необходимо создать её экземпляр с конфигурационным объектом. В нём указывается тип рендерера, размеры холста, цвет фона, родительский HTML-элемент и стартовая сцена.
const config = {
type: Phaser.AUTO,
width: 1280,
height: 720,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
let game = new Phaser.Game(config);
Phaser.AUTO автоматически выбирает между WebGL и Canvas. Размеры width и height задают разрешение игрового мира. Свойство backgroundColor определяет цвет, который будет виден за пределами изображения. Параметр parent — это ID HTML-элемента, в который будет встроен canvas. scene принимает класс сцены, которая будет запущена первой.
Что попробовать дальше
Фильтр виньетирования в Phaser 3 — это мощный и простой инструмент для создания атмосферных эффектов и управления вниманием игрока. Как мы увидели, его можно динамически контролировать прямо во время выполнения игры. Для экспериментов попробуйте связать силу виньетирования со здоровьем персонажа, менять цвет в зависимости от времени суток в игре или привязать центр эффекта `xиy` к положению курсора мыши, создавая эффект фонарика.
