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

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

Версия 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/sprites/blur-bg.png');
    }

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

        this.add.image(width / 2, height / 2, 'bg');

        // This technique requires 4D noise.
        this.noise = this.add.noisecell4d({
            noiseCells: [ 16, 9, 16, 16 ],
            noiseColorStart: [ 0, 0, 0, 0 ],
            noiseColorEnd: [ 1, 1, 13 / 16, 0.5 ]
        }, width / 2, height / 2, width, height)
        .setBlendMode(Phaser.BlendModes.ADD);
    }

    update (time)
    {
        const t = time / 16000;

        // Rotate in ZW.
        // THe pattern repeats, but never loses precision.
        this.noise.noiseOffset[2] = Math.cos(t);
        this.noise.noiseOffset[3] = Math.sin(t);
    }
}

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

const game = new Phaser.Game(config);

Зачем нужен 4D шум?

Обычный 2D или 3D шум (Perlin, Simplex) генерирует статичную текстуру. Для создания бесконечной, плавно изменяющейся анимации (например, вращающейся туманности) нам нужна четвертая ось (W). Думайте об этом как о анимированном 3D-объеме: три оси (X, Y, Z) задают пространственную структуру, а четвертая (W) — время. Перемещаясь по оси W, мы получаем плавную, никогда не повторяющуюся в точности анимацию.

В примере используется noisecell4d — реализация клеточного (ячеистого) шума. В отличие от градиентного шума, он создает текстуру, напоминающую скопления клеток или пузырьков, что отлично подходит для органичных, негеометрических форм.

Разбор создания объекта шума

Основная магия происходит в методе create. После загрузки и отрисовки фонового изображения создается объект 4D шума.

this.noise = this.add.noisecell4d({
    noiseCells: [ 16, 9, 16, 16 ],
    noiseColorStart: [ 0, 0, 0, 0 ],
    noiseColorEnd: [ 1, 1, 13 / 16, 0.5 ]
}, width / 2, height / 2, width, height)
.setBlendMode(Phaser.BlendModes.ADD);

Разберем параметры конструктора: 1. **Конфигурационный объект:** * noiseCells: [X, Y, Z, W] — определяет «зернистость» шума по каждой из четырех осей. Меньшие значения дают более крупные «клетки», большие — более мелкую, детализированную текстуру. * noiseColorStart и noiseColorEnd: [R, G, B, A] — задают цветовой градиент для шума. Значения в диапазоне от 0 до 1. Альфа-канал (A) управляет прозрачностью. В примере конечный синий канал (B) установлен в 13/16, что дает темно-синий оттенок. 2. **Позиция и размер:** Следующие четыре аргумента — `x,y,width,height` — стандартные для игрового объекта Phaser, определяющие его положение и масштаб на экране. 3. **Режим смешивания:** .setBlendMode(Phaser.BlendModes.ADD) накладывает шум на фон в режиме сложения. Это делает светлые участки шума ярче, а темные — практически невидимыми, создавая эффект свечения поверх основного изображения.

Анимация через управление смещением

Чтобы шум «ожил», его нужно анимировать. Это делается в методе update, который вызывается каждый кадр.

update (time)
{
    const t = time / 16000;
    this.noise.noiseOffset[2] = Math.cos(t);
    this.noise.noiseOffset[3] = Math.sin(t);
}

Ключевой момент — изменение свойств массива noiseOffset. Этот массив из 4 элементов отвечает за смещение (сдвиг) по осям X, Y, Z, W соответственно. 1. Мы вычисляем `t— нормализованное время. Делениеtime` на 16000 замедляет анимацию, делая ее плавной. 2. Мы изменяем смещение по осям Z и W (индексы 2 и 3), используя тригонометрические функции Math.cos и Math.sin. Это заставляет точку отсчета шума двигаться по кругу в плоскости ZW.

**Почему это создает бесконечную петлю?** Потому что значения синуса и косинуса периодичны. Когда `t` увеличивается, смещение плавно циклически изменяется от -1 до 1, создавая иллюзию непрерывного, никогда не заканчивающегося вращения или скролла текстуры. Точность JavaScript-чисел гарантирует, что паттерн не «сломается» даже после очень долгого времени работы.

Практические идеи для ваших игр

Понимая принцип, вы можете легко адаптировать этот пример под свои нужды.

* **Изменение скорости и направления:** Поэкспериментируйте с делителем времени (16000) и поменяйте местами cos и sin.

const t = time / 5000; // Более быстрая анимация
this.noise.noiseOffset[2] = Math.sin(t * 0.7); // Разная скорость по осям
this.noise.noiseOffset[3] = Math.cos(t * 1.3);

* **Другой цвет и форма:** Измените noiseColorEnd для получения кислотных, огненных или ледяных эффектов. Увеличьте noiseCells[3] для более плавной анимации во времени.

noiseColorEnd: [ 1, 0.2, 0, 0.8 ] // Оранжево-огненная гамма

* **Сложные паттерны:** Добавьте влияние на смещение по осям X и Y (noiseOffset[0] и noiseOffset[1]) для создания эффекта ветра или течения. * **Несколько слоев:** Создайте 2-3 объекта noisecell4d с разными параметрами и режимами смешивания (SCREEN, MULTIPLY), наложив их друг на друга для получения сложной, многослойной текстуры.

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

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

  1. Связать смещение шума со скоростью игрового корабля для эффекта warp-скорости
  2. Использовать шум в качестве маски для частиц, чтобы они появлялись только в «светлых» областях туманности
  3. Динамически менять цвет шума в зависимости от событий в игре (например, получение урона)