О чем этот пример
Визуальные эффекты, такие как дым, огонь, вода или органические текстуры, часто требуют алгоритмической генерации. Phaser предоставляет мощный инструмент `add.noisecell4d` для создания 4D клеточного шума прямо в Canvas или WebGL. Эта статья покажет, как управлять параметром `noiseIterations` для получения текстур разной детализации и плотности, что идеально подходит для фонов, анимаций частиц или procedural generation.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
noise1;
noise2;
noise3;
create()
{
const { width, height } = this.scale;
const config = {
noiseCells: [ 5, 9, 4, 4 ],
noiseColorStart: 0xffffff,
noiseColorEnd: [ 0, 0, 0, 0 ]
};
this.noise1 = this.add.noisecell4d(config, width * 1 / 6, height / 2, width / 3, height);
this.noise2 = this.add.noisecell4d({
...config,
noiseIterations: 2
}, width * 3 / 6, height / 2, width / 3, height);
this.noise3 = this.add.noisecell4d({
...config,
noiseIterations: 5
}, width * 5 / 6, height / 2, width / 3, height);
this.add.text(10, 10, '1 iteration', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width / 3 + 10, 10, '2 iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width * 2 / 3 + 10, 10, '5 iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
}
update (time)
{
const t = time / 10000;
const c = Math.cos(t);
const s = Math.sin(t);
this.noise1.noiseOffset[0] = c;
this.noise1.noiseOffset[1] = s;
this.noise1.noiseOffset[2] = c / 4;
this.noise1.noiseOffset[3] = s / 4;
this.noise2.noiseOffset[0] = c;
this.noise2.noiseOffset[1] = s;
this.noise2.noiseOffset[2] = c / 4;
this.noise2.noiseOffset[3] = s / 4;
this.noise3.noiseOffset[0] = c;
this.noise3.noiseOffset[1] = s;
this.noise3.noiseOffset[2] = c / 4;
this.noise3.noiseOffset[3] = s / 4;
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1280,
height: 720,
scene: Example
};
const game = new Phaser.Game(config);
Основы: создание шумового объекта
Ключевой метод для работы — this.add.noisecell4d(). Он принимает конфигурационный объект, координаты, ширину и высоту, возвращая игровой объект с динамической текстурой.
Базовый конфиг определяет начальные ячейки и градиент цвета. Обратите внимание: noiseColorEnd задаётся как массив RGBA, где 0 соответствует полной прозрачности.
const config = {
noiseCells: [ 5, 9, 4, 4 ],
noiseColorStart: 0xffffff,
noiseColorEnd: [ 0, 0, 0, 0 ]
};
Создадим первый объект шума, разместив его в левой трети экрана:
this.noise1 = this.add.noisecell4d(config, width * 1 / 6, height / 2, width / 3, height);
Магия итераций: noiseIterations
Параметр noiseIterations — это количество проходов алгоритма шума. Чем больше итераций, тем детальнее и "гуще" становится итоговая текстура. Это похоже на наслоение нескольких шумовых карт.
В примере мы создаём три объекта с разным количеством итераций, используя spread-оператор для копирования базового конфига. Первый объект использует значение по умолчанию (1 итерация), второй — 2, третий — 5.
this.noise2 = this.add.noisecell4d({
...config,
noiseIterations: 2
}, width * 3 / 6, height / 2, width / 3, height);
this.noise3 = this.add.noisecell4d({
...config,
noiseIterations: 5
}, width * 5 / 6, height / 2, width / 3, height);
На практике вы увидите, как текстура слева (1 итерация) — самая простая и разреженная, а справа (5 итераций) — наиболее детализированная и плотная.
Оживляем шум: анимация через noiseOffset
Статичный шум — это скучно. Сила 4D-шума в том, что у него есть четвёртое измерение, которое можно использовать как время. Массив noiseOffset объекта шума позволяет сдвигать шум в его 4D-пространстве, создавая плавную анимацию.
В методе update() мы вычисляем значения на основе времени, используя Math.cos() и Math.sin(). Эти значения затем присваиваются элементам массива noiseOffset. Первые два элемента часто отвечают за смещение по X и Y в 2D-пространстве, а третий и четвёртый — за смещение в дополнительных измерениях шума, что даёт более сложные и органичные паттерны движения.
update (time)
{
const t = time / 10000;
const c = Math.cos(t);
const s = Math.sin(t);
this.noise1.noiseOffset[0] = c;
this.noise1.noiseOffset[1] = s;
this.noise1.noiseOffset[2] = c / 4;
this.noise1.noiseOffset[3] = s / 4;
// ... тоже самое для noise2 и noise3
}
Деление значений для третьего и четвёртого смещения (c / 4, s / 4) замедляет изменение по этим осям, добавляя дополнительный слой сложности к анимации.
Практическое применение в играх
Как использовать этот инструмент?
* **Фоновые текстуры:** Быстро создавайте бесшовные, анимированные фоны для подводных уровней, космоса или магических порталов. * **Эффекты частиц:** Используйте шум как маску или текстуру для систем частиц, чтобы имитировать клубящийся дым или текущую лаву. * **Procedural generation:** Сгенерируйте карту высот или влажности для процедурно создаваемого мира. Несколько итераций шума могут имитировать горные хребты, а одна — равнины.
Экспериментируйте с массивом noiseCells. Эти четыре числа определяют начальное "зерно" или паттерн ячеек. Изменение даже одного числа кардинально меняет итоговый вид текстуры.
// Эксперимент с разными начальными ячейками
const experimentalConfig = {
noiseCells: [ 2, 7, 1, 8 ], // Меняйте эти значения!
noiseColorStart: 0x44aaff,
noiseColorEnd: [ 0, 0, 0, 0 ],
noiseIterations: 3
};
Что попробовать дальше
Метод add.noisecell4d в Phaser — это gateway drug в мир процедурной графики. Управляя noiseIterations и анимируя noiseOffset, вы получаете мощный контроль над сложностью и динамикой текстур. Для экспериментов попробуйте: связать скорость анимации с игровыми событиями (например, ускорить шум при получении урона), комбинировать несколько слоёв шума с разными цветами или использовать значение шума в конкретной точке (через возможные методы объекта, не показанные в примере) для логики игры — например, для определения, находится ли персонаж в 'тумане'.
