О чем этот пример
Создание игр — это не только механика, но и визуальный стиль. Иногда нужно добиться эффекта ограниченной палитры, как в классических пиксель-арт играх или для создания постерного вида. Фильтр `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. Используйте квантование в шейдерах для пост-обработки всей сцены.
