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

Визуальные эффекты на основе процедурного шума — мощный инструмент для создания динамичных фонов, текстур и атмосферных явлений в играх. Phaser предоставляет встроенные объекты для генерации клеточного шума в 2D, 3D и даже 4D пространствах. В этой статье мы разберем, как управлять дополнительными измерениями шума, чтобы создавать анимированные, «живые» текстуры прямо во время выполнения игры, без использования спрайт-листов или видеороликов.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    noise2;
    noise3;

    create()
    {
        const { width, height } = this.scale;

        this.add.noisecell2d({ noiseCells: [ 5, 9] }, width * 1 / 6, height / 2, width / 3, height);
        this.noise2 = this.add.noisecell3d({ noiseCells: [ 5, 9, 1 ] }, width * 3 / 6, height / 2, width / 3, height);
        this.noise3 = this.add.noisecell4d({ noiseCells: [ 5, 9, 1, 1 ] }, width * 5 / 6, height / 2, width / 3, height);

        this.add.text(10, 10, '2D', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
        this.add.text(width / 3 + 10, 10, '3D', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
        this.add.text(width * 2 / 3 + 10, 10, '4D', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
    }

    update (time)
    {
        // Scroll the Z axis.
        // Note that this will lose precision once it reaches high values.

        const t = time / 5000;

        // 2D noise has no extra dimension to offset.

        this.noise2.noiseOffset[2] = t;
        this.noise3.noiseOffset[2] = t;
    }
}

const config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    width: 1280,
    height: 720,
    scene: Example
};

const game = new Phaser.Game(config);

Создание объектов шума: от 2D к 4D

В методе create() сцены создаются три объекта шума, которые визуализируются как текстуры. Ключевое различие между ними — количество измерений.

this.add.noisecell2d({ noiseCells: [ 5, 9] }, width * 1 / 6, height / 2, width / 3, height);
this.noise2 = this.add.noisecell3d({ noiseCells: [ 5, 9, 1 ] }, width * 3 / 6, height / 2, width / 3, height);
this.noise3 = this.add.noisecell4d({ noiseCells: [ 5, 9, 1, 1 ] }, width * 5 / 6, height / 2, width / 3, height);

Каждый вызов метода (noisecell2d, noisecell3d, noisecell4d) создает новый игровой объект типа Noise. Параметр noiseCells — это массив, определяющий детализацию шума в каждом измерении. Например, [5, 9] для 2D означает 5 ячеек по X и 9 по Y. Последующие вызовы добавляют параметры для Z и W осей.

Объекты размещаются на экране друг за другом (на 1/6, 3/6 и 5/6 ширины экрана). Важно, что 3D и 4D объекты сохраняются в свойства класса (this.noise2, this.noise3), чтобы к ним можно было обращаться позже в цикле обновления. 2D-шум не анимируется, поэтому ссылка на него не сохраняется.

Анимация через смещение по оси Z

Динамика эффекту придается в методе update(time). Этот метод вызывается на каждом кадре игры и получает текущее игровое время в миллисекундах.

const t = time / 5000;

Здесь время делится на 5000, чтобы замедлить изменение и сделать анимацию плавной. Переменная `t` постепенно увеличивается с каждой секундой игры.

this.noise2.noiseOffset[2] = t;
this.noise3.noiseOffset[2] = t;

Свойство noiseOffset есть у объектов 3D и 4D шума. Это массив, где индексы 0, 1, 2 соответствуют смещению по осям X, Y, Z соответственно. Присваивая значение `tиндексу[2]`, мы непрерывно сдвигаем «срез» шума по оси Z. Визуально это создает эффект плавного, бесшовного скроллинга текстуры. Для 4D-шума это работает аналогично, так как четвертое измерение (W) остается статичным.

Важное замечание из кода: при очень больших значениях `t` может произойти потеря точности вычислений, что потенциально скажется на визуальном качестве.

Практическое применение и настройка

Где это можно использовать? Анимированный 3D/4D шум идеально подходит для: * Фоновых переливов (лава, туман, вода). * Генерации динамических текстур для магии или щитов. * Создания «живых» поверхностей планет или астероидов.

Экспериментируйте с параметрами:

// Увеличение детализации (больше ячеек)
{ noiseCells: [10, 20, 3] }
// Анимация по другой оси или с другой скоростью
this.noise2.noiseOffset[0] = time / 10000; // Медленный скролл по X
// Одновременное движение по нескольким осям
this.noise3.noiseOffset[1] = time / 7000;
this.noise3.noiseOffset[2] = time / 5000;

Изменяя массив noiseCells, вы контролируете «зернистость» паттерна. Меньшие значения дают крупные, четкие ячейки, большие — мелкую, сложную текстуру. Комбинируя скорости смещения по разным осям, можно получить сложные, не повторяющиеся анимации.

Что попробовать дальше

Использование многомерного клеточного шума в Phaser открывает простой путь к созданию производительных и визуально интересных динамических эффектов прямо в коде. Вы управляете анимацией через смещение в дополнительном измерении, что эффективнее, чем проигрывание спрайт-листа. Для экспериментов попробуйте: 1. Привязать смещение noiseOffset не ко времени, а к скорости игрового персонажа, чтобы шум на фоне реагировал на движение. 2. Использовать 4D-шум, анимируя и третье измерение (noiseOffset[3]), для получения еще более сложных трансформаций. 3. Наложить на шум цветовой градиент через шейдер для создания эффекта плазмы или энергетического поля.