О чем этот пример
Визуальные эффекты — ключевой элемент погружения в игре. Один из мощных, но малоизвестных инструментов Phaser 3 — фильтр `CombineColorMatrixFilter`. Он позволяет использовать яркость одной текстуры в качестве альфа-канала для другой, создавая сложные, динамические маски и эффекты наложения. В этой статье мы разберем практический пример, показывающий, как с помощью этого фильтра управлять прозрачностью двух изображений на основе третьего и анимировать результат.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
g1;
g2;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('distortion', 'assets/textures/distortion7.png');
this.load.image('gradient1', 'assets/skies/gradient1.png');
this.load.image('gradient2', 'assets/skies/gradient2.png');
}
create ()
{
const bg = this.add.image(640, 360, 'distortion').setAlpha(0.1);
Phaser.Actions.FitToRegion(bg, 1);
// Use brightness from `distortion` as an alpha channel.
const g1 = this.add.image(640, 360, 'gradient1');
const g1Combine = g1.enableFilters().filters.internal.addCombineColorMatrix('distortion');
g1Combine.setupAlphaTransfer(true, false, undefined, true);
this.g1 = g1;
// Invert the brightness-derived alpha.
const g2 = this.add.image(640, 360, 'gradient2');
const g2Combine = g2.enableFilters().filters.internal.addCombineColorMatrix('distortion');
g2Combine.setupAlphaTransfer(true, false, undefined, undefined, undefined, true);
this.g2 = g2;
}
update (time, delta)
{
const d = 128 * Math.sin(time / 3000);
this.g1.x = 640 + d;
this.g2.x = 640 - d;
}
}
const config = {
type: Phaser.WEBGL,
width: 1280,
height: 720,
backgroundColor: '#2d3440',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка и загрузка ресурсов
Как и в любом проекте на Phaser, работа начинается с загрузки ресурсов. В методе preload мы указываем базовый URL и загружаем три текстуры: distortion, gradient1 и gradient2. Текстура distortion будет выступать в роли карты яркости (или альфа-карты) для двух градиентов.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('distortion', 'assets/textures/distortion7.png');
this.load.image('gradient1', 'assets/skies/gradient1.png');
this.load.image('gradient2', 'assets/skies/gradient2.png');
Создание фона и базовых изображений
В методе create мы сначала добавляем на сцену текстуру distortion в качестве фона. С помощью setAlpha(0.1) мы делаем её едва заметной, чтобы она не отвлекала от основного эффекта. Метод Phaser.Actions.FitToRegion растягивает изображение на всю сцену.
Затем создаются два основных изображения с градиентами (gradient1 и gradient2). Они будут центрированы на экране и станут носителями нашего визуального эффекта.
const bg = this.add.image(640, 360, 'distortion').setAlpha(0.1);
Phaser.Actions.FitToRegion(bg, 1);
const g1 = this.add.image(640, 360, 'gradient1');
const g2 = this.add.image(640, 360, 'gradient2');
Применение фильтра CombineColorMatrixFilter
Это ключевой этап. Для изображения g1 мы включаем систему фильтров с помощью enableFilters(). Затем, обращаясь к внутреннему менеджеру фильтров filters.internal, добавляем фильтр типа addCombineColorMatrix. В его конструктор передается ключ текстуры distortion. Теперь этот фильтр «знает» о карте яркости.
Метод setupAlphaTransfer настраивает, как именно яркость текстуры-источника будет преобразована в альфа-канал целевого изображения. Первый параметр true включает использование красного канала источника (в оттенках серого R=G=B, поэтому подойдет любой). Следующие параметры управляют инверсией. Для g1 мы передаем true в последний параметр, что означает: *использовать яркость как есть*. Для g2 мы передаем true в предпоследний параметр, что *инвертирует* полученную альфу.
const g1Combine = g1.enableFilters().filters.internal.addCombineColorMatrix('distortion');
g1Combine.setupAlphaTransfer(true, false, undefined, true);
const g2Combine = g2.enableFilters().filters.internal.addCombineColorMatrix('distortion');
g2Combine.setupAlphaTransfer(true, false, undefined, undefined, undefined, true);
Анимация результата
Чтобы эффект не был статичным, мы добавляем простую анимацию в методе update. На основе синусоидальной функции от времени вычисляется смещение `d. Затем мы двигаем два наших изображения с градиентами в противоположные стороны. Так как их прозрачность привязана к одной и той же текстуреdistortion`, но с инвертированной альфой для второго, создается эффект плавного перетекания одного изображения в другое.
update (time, delta)
{
const d = 128 * Math.sin(time / 3000);
this.g1.x = 640 + d;
this.g2.x = 640 - d;
}
Конфигурация игры
Пример использует контекст рендеринга WEBGL, так как фильтры требуют поддержки WebGL. Задаются размеры окна, цвет фона и указывается класс сцены.
const config = {
type: Phaser.WEBGL,
width: 1280,
height: 720,
backgroundColor: '#2d3440',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Фильтр CombineColorMatrixFilter открывает тонкий контроль над наложением изображений, позволяя создавать эффекты маскирования, плавных переходов и динамических текстур на основе яркости. Для экспериментов попробуйте: использовать разные текстуры в качестве источника альфы (например, шум Перлина или рендер сцены); анимировать не положение, а параметры самого фильтра; комбинировать этот фильтр с другими, например, с BlurFilter для создания эффекта расфокусировки на краях маски.
