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