О чем этот пример

Фильтры в Phaser 3 — мощный инструмент для постобработки графики, но что если вам нужно проанализировать результат их работы? Пример `sampler.js` демонстрирует редкую возможность: взятие пробы цвета (`sampler`) с изображения, к которому уже применены другие фильтры. Это открывает двери для создания динамических визуальных связей, например, когда цвет фона сцены синхронизируется с цветом определенной точки на обработанном спрайте, независимо от действующих на нем эффектов пикселизации и размытия.

Версия 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('card2', 'assets/pics/card2.png');
    }

    create ()
    {
        const card = this.add.image(640, 360, 'card2');

        // Add filters to the card.
        card.enableFilters();

        // Pixelate the card.
        const pixelate = card.filters.internal.addPixelate(30);

        // Sample the card at the center and update the background color.
        card.filters.internal.addSampler((color) => {
            this.game.renderer.config.backgroundColor = color;
        }, { x: 142, y: 200 });

        // Blur the card. The sampler is unaffected.
        const blur = card.filters.internal.addBlur(0, 2, 2, 2);
        blur.setPaddingOverride(null);

        this.tweens.add({
            targets: pixelate,
            amount: -1,
            duration: 10000,
            yoyo: true,
            loop: -1
        });

        this.tweens.add({
            targets: blur,
            strength: 0,
            duration: 10000,
            yoyo: true,
            loop: -1
        });
    }
}

const config = {
    type: Phaser.AUTO,
    width: 1280,
    height: 720,
    backgroundColor: '#000000',
    parent: 'phaser-example',
    scene: Example
};

let game = new Phaser.Game(config);

Подготовка сцены и загрузка ресурсов

Как и в любой сцене Phaser, работа начинается с методов жизненного цикла. В preload() мы загружаем единственное изображение — карту. Обратите внимание на использование setBaseURL, которое позволяет задать базовый путь для всех последующих загрузок, что удобно для работы с внешними ресурсами.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('card2', 'assets/pics/card2.png');
}

В create() мы создаем основной спрайт — карту — и сразу разрешаем применение к нему фильтров с помощью метода enableFilters(). Без этого вызова система фильтров для этого спрайта будет неактивна.

const card = this.add.image(640, 360, 'card2');
card.enableFilters();

Добавление фильтров: порядок имеет значение

Фильтры применяются к спрайту в том порядке, в котором они добавлены. Внутренний менеджер фильтров доступен через card.filters.internal. Первым делом добавляется пикселизация с высоким значением amount (30), что сильно увеличит размер видимых пикселей.

const pixelate = card.filters.internal.addPixelate(30);

Следующим идет ключевой элемент примера — Sampler. Это особый фильтр, который не изменяет изображение, а берет пробу цвета в указанной точке (относительно спрайта с уже примененными до него фильтрами) и передает этот цвет в callback-функцию. Точка { x: 142, y: 200 } — это координата внутри спрайта карты.

card.filters.internal.addSampler((color) => {
    this.game.renderer.config.backgroundColor = color;
}, { x: 142, y: 200 });

Затем добавляется фильтр размытия. Важный нюанс: чтобы размытие не "вылезало" за границы спрайта и не влияло на пробу, его padding отменяется через setPaddingOverride(null). Фильтр Sampler, добавленный до размытия, будет брать цвет с уже пикселизированного, но еще не размытого изображения.

const blur = card.filters.internal.addBlur(0, 2, 2, 2);
blur.setPaddingOverride(null);

Анимация параметров фильтров

Для наглядности параметры добавленных фильтров анимируются с помощью системы твинов Phaser. Твин для пикселизации плавно меняет amount от 30 до -1 и обратно, создавая эффект "дыхания" пикселей. Значение -1 практически отключает фильтр.

this.tweens.add({
    targets: pixelate,
    amount: -1,
    duration: 10000,
    yoyo: true,
    loop: -1
});

Аналогичный твин применяется к силе размытия (strength), меняя ее от 2 до 0. Это создает циклическое появление и исчезновение эффекта размытия. Обратите внимание, что анимация strength не влияет на работу Sampler — он продолжает сэмплировать цвет на этапе, предшествующем размытию.

this.tweens.add({
    targets: blur,
    strength: 0,
    duration: 10000,
    yoyo: true,
    loop: -1
});

Конфигурация игры и запуск

Код завершается стандартной конфигурацией игры. Ключевой момент — изначальный цвет фона задан черным (#000000), но он будет мгновенно переопределен в callback Sampler'а при создании сцены.

const config = {
    type: Phaser.AUTO,
    width: 1280,
    height: 720,
    backgroundColor: '#000000',
    parent: 'phaser-example',
    scene: Example
};

let game = new Phaser.Game(config);

Что попробовать дальше

Пример наглядно показывает, как Sampler работает в конвейере фильтров: он сэмплирует цвет на том этапе обработки, на котором был добавлен, игнорируя последующие эффекты. Это мощный инструмент для создания обратной связи между визуальными элементами. Для экспериментов попробуйте

  1. Изменить координаты сэмплирования в реальном времени, следя за курсором мыши
  2. Использовать полученный цвет не для фона, а для окрашивания других спрайтов или частиц
  3. Добавить несколько Sampler'ов в разные точки изображения и смешивать полученные цвета