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

Создание игр — это не только механика, но и визуальный стиль. Иногда нужно добиться эффекта ограниченной палитры, как в классических пиксель-арт играх или для создания постерного вида. Фильтр `Quantize` в Phaser позволяет автоматически уменьшать количество цветов в графике, открывая путь к быстрой и контролируемой стилизации. Эта статья покажет, как превратить плавный градиент в полосатый или пикселизированный, используя встроенные возможности рендеринга. Вы научитесь управлять цветовыми каналами, добавлять дизеринг для сглаживания переходов и применять эти техники к любым игровым объектам.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        this.add.text(640, 50, 'Original gradient').setOrigin(0.5);
        const gradient1 = this.add.gradient({
            bands: {
                colorStart: 0xff0000,
                colorEnd: 0xff0001,
                colorSpace: 2
            }
        }, 640, 150, 1280, 128);

        this.add.text(640, 250, 'Quantized gradient').setOrigin(0.5);
        const gradient2 = this.add.gradient({
            bands: {
                colorStart: 0xff0000,
                colorEnd: 0xff0001,
                colorSpace: 2
            }
        }, 640, 350, 1280, 128);
        gradient2.enableFilters().filters.internal.addQuantize({
            steps: [ 8, 2, 2, 2 ],
            mode: 1 // HSVA
        });

        this.add.text(640, 450, 'Quantized gradient with dither').setOrigin(0.5);
        const gradient3 = this.add.gradient({
            bands: {
                colorStart: 0xff0000,
                colorEnd: 0xff0001,
                colorSpace: 2
            }
        }, 640, 550, 1280, 128);
        gradient3.enableFilters().filters.internal.addQuantize({
            steps: [ 8, 2, 2, 2 ],
            mode: 1, // HSVA
            dither: true
        });
    }
}

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

let game = new Phaser.Game(config);

Подготовка базового градиента

Прежде чем квантовать, нужно создать исходное изображение. В примере используется объект gradient с особыми настройками.

const gradient1 = this.add.gradient({
    bands: {
        colorStart: 0xff0000,
        colorEnd: 0xff0001,
        colorSpace: 2
    }
}, 640, 150, 1280, 128);

Ключевой момент — параметры в объекте bands. colorStart и colorEnd задают начальный и конечный цвет градиента. Разница всего в один младший байт (0xff0000 и 0xff0001) создает очень плавный переход от красного к почти идентичному оттенку. Значение colorSpace: 2 указывает, что градиент строится в цветовом пространстве **HSVA** (Hue, Saturation, Value, Alpha), а не в стандартном RGB. Это важно для последующего квантования, которое также будет работать в HSVA.

Применение фильтра Quantize

Фильтр Quantize уменьшает количество дискретных значений в каждом цветовом канале. Чтобы применить фильтр, объект должен сначала разрешить их использование.

gradient2.enableFilters().filters.internal.addQuantize({
    steps: [ 8, 2, 2, 2 ],
    mode: 1 // HSVA
});

Метод enableFilters() активирует систему фильтров для этого объекта. Далее мы обращаемся к внутреннему менеджеру фильтров filters.internal и добавляем новый фильтр addQuantize.

Конфигурация фильтра: - steps: массив из четырех чисел. Каждое число определяет, на сколько уровней (шагов) будет разбит соответствующий канал цвета. Порядок каналов зависит от mode. При mode: 1 (HSVA) порядок: **Hue (Оттенок), Saturation (Насыщенность), Value (Яркость), Alpha (Прозрачность)**. Значения [8, 2, 2, 2] означают, что оттенок будет иметь 8 возможных уровней, а насыщенность, яркость и прозрачность — только по 2 уровня каждый. Это резко «уплощает» градиент, создавая четкие цветовые полосы (постерный эффект). - mode: 1 — явное указание использовать цветовое пространство HSVA для квантования. Это согласуется с colorSpace при создании градиента.

Добавление дизеринга для сглаживания

Резкие переходы между цветовыми полосами могут выглядеть слишком грубо. Дизеринг — это техника добавления мелкого, случайного шума для визуального смешивания соседних цветов и создания иллюзии большего количества оттенков.

gradient3.enableFilters().filters.internal.addQuantize({
    steps: [ 8, 2, 2, 2 ],
    mode: 1, // HSVA
    dither: true
});

Единственное отличие от предыдущего блока — параметр dither: true. Фильтр начнет применять алгоритм дизеринга (скорее всего, упрощенный Флойда-Стейнберга или подобный) к результату квантования. Вместо резких границ между полосами появятся зернистые переходы, которые выглядят более естественно для человеческого глаза, имитируя глубину цвета. Этот прием особенно ценен при создании ретро-стилистики.

Практическое применение в играх

Фильтр Quantize — это не только для градиентов. Его можно применить к любому игровому объекту, поддерживающему фильтры: Image, Sprite, TileSprite, RenderTexture и даже контейнерам.

// Пример: стилизация спрайта персонажа под пиксель-арт
const hero = this.add.sprite(400, 300, 'hero');
hero.enableFilters().filters.internal.addQuantize({
    steps: [ 6, 4, 4, 2 ], // Поиграйте с значениями
    mode: 0, // Используем RGB для спрайтов
    dither: true
});

Экспериментируйте с массивом steps. Например, [16, 1, 1, 1] в режиме HSVA даст 16 разных оттенков при максимальной насыщенности и яркости — классическая палитра старой игры. Применение фильтра к целой сцене через RenderTexture может мгновенно изменить визуальный стиль всей игры, создавая эффект «цветовой схемы» или резкой смены атмосферы.

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

Фильтр Quantize в Phaser — мощный инструмент для программируемой стилизации графики. Он позволяет быстро перейти от плавных цветовых переходов к ограниченной палитре, что незаменимо для создания пиксель-арт эстетики, постерных эффектов или симуляции дисплеев с низкой глубиной цвета. Идеи для экспериментов: 1. Примените фильтр с разными значениями steps к анимированному спрайту и посмотрите, как ведет себя анимация. 2. Создайте управляемый ползунками интерфейс для изменения параметров steps и dither в реальном времени. 3. Комбинируйте Quantize с другими фильтрами, например Glow или Blur, для создания сложных визуальных эффектов. 4. Используйте квантование в шейдерах для пост-обработки всей сцены.