О чем этот пример
Визуальные эффекты, основанные на шуме, могут оживить игру, добавив атмосферы и реализма. В этом примере мы используем симплекс-шум в Phaser для создания динамичного эффекта искажения «горячего воздуха» (heat haze) на фоновом изображении. Вы узнаете, как генерировать шумовую текстуру, применять ее как карту смещения (displacement map) и анимировать в реальном времени, создавая иллюзию дрожащего воздуха над горячими поверхностями или в космических искажениях.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
noise;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/pics/space-wreck.jpg');
this.load.image('chillno', 'assets/pics/touhou1.png');
}
create()
{
const { width, height } = this.scale;
this.noise = this.add.noisesimplex2d({
noiseCells: [ 9, 9 ],
noiseIterations: 2,
noiseNormalMap: true,
}, 0, 0, width / 8, height / 8).setRenderToTexture('noise');
const bg = this.add.image(width / 2, height / 2 + 128, 'bg').setScale(1.7);
bg.enableFilters().filters.internal.addDisplacement('noise', 0.1);
this.add.image(400, height, 'chillno').setOrigin(0, 1);
}
update (time)
{
const t = time / 1000;
this.noise.noiseFlow = t % (Math.PI * 2);
this.noise.noiseOffset = [ -t, -t ];
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1280,
height: 720,
scene: Example
};
const game = new Phaser.Game(config);
Инициализация шума: основа эффекта
Эффект создается с помощью объекта симплекс-шума, который генерирует текстуру. Эта текстура позже будет использоваться для искажения изображения.
Ключевые параметры при создании:
- noiseCells: определяет детализацию шума (больше значений — более мелкий узор).
- noiseIterations: контролирует сложность шума (наложение нескольких слоев).
- noiseNormalMap: если true, генерирует данные, подходящие для карты смещения.
- Последние четыре аргумента задают позицию и размер генерируемой области шума в пикселях.
Метод .setRenderToTexture('noise') сохраняет сгенерированный шум в текстуру с именем 'noise' для последующего использования.
this.noise = this.add.noisesimplex2d({
noiseCells: [ 9, 9 ],
noiseIterations: 2,
noiseNormalMap: true,
}, 0, 0, width / 8, height / 8).setRenderToTexture('noise');
Применение фильтра смещения к изображению
Чтобы создать эффект искажения, мы применяем к фоновому изображению фильтр смещения (displacement filter). Этот фильтр использует ранее созданную шумовую текстуру для смещения пикселей изображения.
Сначала мы добавляем фоновое изображение и активируем для него систему фильтров с помощью .enableFilters(). Затем, обращаясь к внутреннему менеджеру фильтров .filters.internal, добавляем фильтр смещения addDisplacement. Первый аргумент — имя текстуры-источника ('noise'), второй — сила эффекта (в данном случае 0.1).
const bg = this.add.image(width / 2, height / 2 + 128, 'bg').setScale(1.7);
bg.enableFilters().filters.internal.addDisplacement('noise', 0.1);
Анимация шума в реальном времени
Статичный эффект смещения выглядит неестественно. Чтобы создать иллюзию потока горячего воздуха, мы анимируем параметры шума в методе update. Это функция, которая вызывается каждый кадр.
Мы используем время, прошедшее с начала работы сцены (time), для расчета параметров noiseFlow и noiseOffset. noiseFlow плавно меняет фазу шума, создавая волнообразное движение. noiseOffset сдвигает всю текстуру шума по осям X и Y, имитируя постоянный дрейф.
update (time)
{
const t = time / 1000; // Конвертируем миллисекунды в секунды
this.noise.noiseFlow = t % (Math.PI * 2); // Циклическое изменение фазы
this.noise.noiseOffset = [ -t, -t ]; // Постоянное смещение текстуры
}
Настройка сцены и конфигурации игры
Для работы фильтров смещения, которые используют WebGL, важно указать правильный тип рендерера в конфигурации игры. В данном примере используется Phaser.WEBGL. Также задаются базовые параметры, такие как размер холста и главная сцена.
const config = {
type: Phaser.WEBGL, // Обязательно WEBGL для фильтров
parent: 'phaser-example',
width: 1280,
height: 720,
scene: Example // Наша сцена с эффектом
};
const game = new Phaser.Game(config);
Что попробовать дальше
Вы создали динамичный эффект горячего воздуха, используя симплекс-шум и фильтр смещения в Phaser. Этот подход открывает множество возможностей: попробуйте изменить параметры noiseCells и noiseIterations для получения другой текстуры, увеличьте силу смещения для более агрессивного искажения или примените эффект не ко всему фону, а к конкретным объектам (например, к выхлопам двигателя). Экспериментируя с анимацией noiseOffset, можно имитировать направленный ветер или другие атмосферные явления.
