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

Визуальные эффекты, основанные на шуме, могут оживить игру, добавив атмосферы и реализма. В этом примере мы используем симплекс-шум в 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, можно имитировать направленный ветер или другие атмосферные явления.