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

Фильтры — мощный инструмент для постобработки графики в играх. В этом примере мы рассмотрим, как применить градиентную карту (gradient map) к изображению в Phaser 3. Этот метод позволяет динамически перекрашивать текстуры, создавая психоделические эффекты, смену времени суток или стилизованные визуальные переходы без подготовки множества отдельных ассетов. Вы научитесь настраивать сложные многосегментные градиенты и анимировать их параметры в реальном времени, что откроет новые возможности для визуального оформления игр.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    pic;
    gradientMap;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('pic', 'assets/skies/deep-space.jpg');
    }

    create ()
    {
        this.pic = this.add.image(640, 360, 'pic').setScale(3);
        this.gradientMap = this.pic.enableFilters().filters.internal.addGradientMap({
            ramp: [
                {
                    colorStart: 0x0080a0,
                    colorEnd: 0x402040,
                    colorSpace: 1,
                    size: 0.06
                },
                {
                    colorStart: 0x402040,
                    colorEnd: 0x808020,
                    colorSpace: 1,
                    size: 0.06
                },
                {
                    colorStart: 0x808020,
                    colorEnd: 0x80a040,
                    colorSpace: 1,
                    size: 0.06
                },
                {
                    colorStart: 0x80a040,
                    colorEnd: 0x80a0a0,
                    colorSpace: 1,
                    size: 0.06
                },
                {
                    colorStart: 0x80a0a0,
                    colorEnd: 0x000000,
                    colorSpace: 1
                },
            ]
        });
    }

    update (time, delta)
    {
        this.pic.rotation = time / 7654;
        this.gradientMap.alpha = 0.5 + 0.5 * Math.cos(time / 1000);
    }
}

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 и загружаем одно изображение — фоновую картинку.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('pic', 'assets/skies/deep-space.jpg');
}

После загрузки, в методе create, изображение добавляется на сцену с помощью this.add.image. Важный момент — мы сразу масштабируем его в три раза методом .setScale(3), чтобы оно заполнило нашу сцену размером 1280x720. Это демонстрационный приём; в реальном проекте вы, вероятно, использовали бы изображение подходящего размера.

Включение фильтров и создание градиентной карты

Ключевой шаг — активация системы фильтров для конкретного игрового объекта. Для изображения this.pic вызывается метод .enableFilters(). Этот метод возвращает объект Filters, который управляет всеми фильтрами, применёнными к этому объекту.

this.gradientMap = this.pic.enableFilters().filters.internal.addGradientMap({
    ramp: [
        {
            colorStart: 0x0080a0,
            colorEnd: 0x402040,
            colorSpace: 1,
            size: 0.06
        },
        // ... другие сегменты градиента
    ]
});

Фильтр GradientMap создаётся через filters.internal.addGradientMap. Ему передаётся конфигурационный объект с массивом ramp. Каждый элемент этого массива описывает один сегмент градиента: colorStart и colorEnd (цвета в формате HEX), colorSpace (1 — линейная интерполяция) и size (доля от общей карты, которую занимает этот сегмент). Последний сегмент может не иметь size — он автоматически займёт оставшееся пространство. Эта цепочка сегментов и формирует итоговую палитру для перекрашивания пикселей исходного изображения.

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

Настоящая магия происходит в методе update, который вызывается каждый кадр. Здесь мы анимируем два свойства, используя переданное игровое время (time в миллисекундах).

update (time, delta)
{
    this.pic.rotation = time / 7654;
    this.gradientMap.alpha = 0.5 + 0.5 * Math.cos(time / 1000);
}
Первая строка медленно вращает само изображение (`this.pic.rotation`), используя линейную зависимость от времени.
Вторая строка создает пульсацию прозрачности (альфа-канала) самого фильтра градиентной карты (`this.gradientMap.alpha`). Значение колеблется между 0 и 1 по косинусоидальному закону, создавая эффект периодического проявления и исчезновения цветового эффекта. Это демонстрирует, что свойства фильтров можно менять динамически, как и любые другие свойства игровых объектов.

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

Весь пример завершается стандартной для Phaser конфигурацией и созданием экземпляра игры.

const config = {
    type: Phaser.WEBGL, // Важно: фильтры работают только с WEBGL
    width: 1280,
    height: 720,
    backgroundColor: '#2d3440',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Критически важный параметр — type: Phaser.WEBGL. Фильтры, включая градиентные карты, требуют для своей работы WebGL-рендерера и не будут функционировать в режиме Phaser.CANVAS. Также обратите внимание, что родительский контейнер (parent) должен существовать в вашем HTML.

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

Градиентные карты в Phaser — это гибкий инструмент для программируемого цветокоррекции и стилизации. Вы можете использовать их не только для фонов, но и для спрайтов персонажей, эффектов интерфейса или передачи настроения уровня. **Идеи для экспериментов:** 1. Свяжите параметры градиента (например, colorStart первого сегмента) с игровыми событиями — здоровьем игрока или временем на таймере. 2. Создайте несколько пресетов градиентов (день/ночь, ярость/спокойствие) и плавно переключайтесь между ними, интерполируя цвета. 3. Примените градиентную карту не к статичному изображению, а к анимированному спрайту или системе частиц и наблюдайте за трансформацией.