О чем этот пример
Визуальные эффекты — важная часть игрового опыта. Статичные фоны и текстуры могут быстро наскучить. В Phaser 3.60 появился мощный объект `Gradient`, позволяющий создавать и анимировать программные градиенты прямо во время выполнения игры. Это открывает двери для генерации динамичных фонов, психоделических эффектов и даже использования градиентов в качестве карт смещения для других объектов. В этой статье мы разберем пример, где анимированный радиальный градиент используется как источник волн для эффекта дисторсии на фоновом изображении. Вы научитесь создавать объекты `Gradient`, настраивать их форму и цветовые переходы, а затем в реальном времени изменять их свойства для создания анимации.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
gradient;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('sky', 'assets/skies/chrome.png');
}
create ()
{
this.gradient = this.add.gradient({
repeatMode: 3, // TRIANGULAR
start: { x: 0.5, y: 0.5 },
shape: { x: 0.02, y: 0 },
shapeMode: 2, // RADIAL
dither: true,
bands: [
{
colorStart: 0xffffff,
colorEnd: 0x000000,
interpolation: 2
}
]
}, 400, 300, 800, 600);
// Necessary for captureFrame:
this.cameras.main.setForceComposite(true);
this.add.captureFrame('ripples');
this.add.image(400, 300, 'sky')
.setScale(1.1)
.setAlpha(0.9)
.enableFilters()
.filters.internal.addDisplacement('ripples');
}
update (time)
{
this.gradient.offset = time / 400;
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание объекта Gradient
Основной инструмент в нашем примере — объект Gradient. Он создается в методе create() сцены с помощью метода this.add.gradient(). Этот метод принимает объект конфигурации и параметры размера.
Конфигурация градиента задает его ключевые визуальные свойства:
this.gradient = this.add.gradient({
repeatMode: 3, // TRIANGULAR
start: { x: 0.5, y: 0.5 },
shape: { x: 0.02, y: 0 },
shapeMode: 2, // RADIAL
dither: true,
bands: [
{
colorStart: 0xffffff,
colorEnd: 0x000000,
interpolation: 2
}
]
}, 400, 300, 800, 600);
- `repeatMode: 3`: Устанавливает треугольный режим повторения градиента (`Phaser.Types.GameObjects.Gradient.GRADIENT_REPEAT.TRIANGULAR`). Это создает плавные волны от центра к краям.
- `start: { x: 0.5, y: 0.5 }`: Определяет точку начала градиента в центре объекта (координаты от 0 до 1).
- `shape: { x: 0.02, y: 0 }` и `shapeMode: 2`: Вместе задают радиальную форму (`RADIAL`) градиента. Параметр `shape.x` влияет на «растяжение» градиента.
- `dither: true`: Включает дизеринг для сглаживания цветовых переходов и уменьшения полос.
- `bands`: Массив, определяющий цветовые полосы. В примере одна полоса — плавный переход от белого (`0xffffff`) к черному (`0x000000`) с интерполяцией.
Последние четыре числа (`400, 300, 800, 600`) — это координаты `x`, `y`, ширина и высота объекта градиента на сцене.
Использование градиента как карты смещения
Сам по себе анимированный градиент может служить фоном. Но в примере показана более продвинутая техника: использование его в качестве карты смещения (displacement map) для другого графического объекта. Этот эффект создает иллюзию волн или ряби на изображении.
Сначала необходимо подготовить градиент к использованию в качестве текстуры для фильтра. Для этого используется система захвата кадров (CaptureFrame).
// Необходимо для корректной работы захвата кадра:
this.cameras.main.setForceComposite(true);
this.add.captureFrame('ripples');
Метод setForceComposite(true) гарантирует, что градиент будет отрендерен в отдельный слой. Метод this.add.captureFrame('ripples') создает текстуру с именем 'ripples', в которую будет постоянно записываться текущий кадр градиента.
Затем создается фоновое изображение (sky), и к нему применяется фильтр смещения, который использует нашу текстуру 'ripples' в качестве карты.
this.add.image(400, 300, 'sky')
.setScale(1.1)
.setAlpha(0.9)
.enableFilters()
.filters.internal.addDisplacement('ripples');
Цепочка методов:
- .enableFilters() — активирует систему фильтров для этого игрового объекта.
- .filters.internal.addDisplacement('ripples') — добавляет фильтр смещения и указывает, что в качестве карты смещения (displacementMap) следует использовать текстуру с именем 'ripples', которая автоматически обновляется нашим градиентом.
Анимация градиента в реальном времени
Динамика эффекта достигается за счет изменения свойства градиента в методе update(), который вызывается на каждом кадре игры.
update (time)
{
this.gradient.offset = time / 400;
}
Параметр time — это встроенная переменная Phaser, содержащая текущее время игры в миллисекундах. Присваивая значение time / 400 свойству this.gradient.offset, мы плавно сдвигаем (смещаем) градиент. Поскольку градиент имеет треугольный режим повторения (TRIANGULAR), это смещение создает плавную пульсирующую волну, расходящуюся от центра.
Это непрерывное изменение offset приводит к тому, что каждый кадр градиента ('ripples') немного отличается от предыдущего. Фильтр смещения, примененный к фону, считывает эту изменяющуюся текстуру и соответствующим образом искажает изображение, создавая анимацию ряби.
Конфигурация игры и запуск
Для запуска примера необходима стандартная конфигурация игры Phaser.
const config = {
type: Phaser.WEBGL, // Важно использовать WEBGL для работы с градиентами и фильтрами
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example // Наша сцена с градиентом
};
const game = new Phaser.Game(config);
Ключевой момент — использование type: Phaser.WEBGL. Градиенты и многие продвинутые эффекты, включая фильтры, работают только в контексте WebGL-рендерера Phaser. Рендерер Canvas их не поддерживает.
Что попробовать дальше
Объект Gradient в Phaser — мощный инструмент для создания динамичной графики без использования внешних ресурсов. Как показано в примере, его можно не только отрисовывать напрямую, но и использовать в качестве живой текстуры для пост-обработки других объектов через фильтры.
**Идеи для экспериментов:**
1. Измените параметры bands, добавив несколько цветовых полос или изменив алгоритм интерполяции.
2. Поэкспериментируйте с shapeMode и repeatMode, чтобы получить линейные, конусные или другие типы градиентов.
3. Анимируйте не только offset, но и другие свойства, например shape.x или start, чтобы градиент "дышал" или двигался по сложной траектории.
4. Используйте несколько градиентов с разными настройками и наложите их друг на друга с помощью режимов наложения (blendMode).
5. Примените градиент как карту смещения к спрайту персонажа для создания эффекта теплового марева или искажения при получении урона.
