О чем этот пример
Генерация процедурного контента — ключ к созданию уникальных и бесконечных миров. Phaser предоставляет мощный инструмент `add.noisesimplex2d` для работы с симплексным шумом, но его настоящая сила раскрывается в параметрах искажения (warp). Эта статья покажет, как, манипулируя всего несколькими свойствами, вы можете кардинально менять характер процедурной текстуры — от быстрой детализации до гипнотического потока. Эти техники полезны для создания фонов, текстур ландшафта, магических эффектов или динамичных небес.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
noise1;
noise2;
noise3;
noise4;
create()
{
const { width, height } = this.scale;
// Four variants, differing only in noise warp adjustments.
this.noise1 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2
}, width * 1 / 8, height / 2, width / 4, height);
this.noise2 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2,
noiseWarpDetailPower: 4 // Increase detail quickly.
}, width * 3 / 8, height / 2, width / 4, height);
this.noise3 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2,
noiseWarpContributionPower: 1 // Subsequent octaves decay slower.
}, width * 5 / 8, height / 2, width / 4, height);
this.noise4 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2,
noiseWarpFlowPower: 8 // Subsequent octaves flow faster
}, width * 7 / 8, height / 2, width / 4, height);
this.add.text(10, 10, 'Default warp', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width / 4 + 10, 10, 'Detail +', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width / 2 + 10, 10, 'Contribution decay -', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width * 3 / 4 + 10, 10, 'Flow +', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
}
update (time)
{
const t = (time / 1000) % (Math.PI * 2);
this.noise1.noiseFlow = t;
this.noise2.noiseFlow = t;
this.noise3.noiseFlow = t;
this.noise4.noiseFlow = t;
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1280,
height: 720,
scene: Example
};
const game = new Phaser.Game(config);
Основа: создание объекта шума
Класс Example расширяет Phaser.Scene. В методе create мы создаем четыре варианта симплексного шума, используя метод this.add.noisesimplex2d. Каждый объект размещается на своей позиции по горизонтали и имеет одинаковый базовый размер.
this.noise1 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2
}, width * 1 / 8, height / 2, width / 4, height);
Здесь noiseCells задает количество ячеек шума по осям X и Y (влияет на масштаб паттерна). noiseWarpAmount определяет силу искажения, а noiseWarpIterations — количество октав (слоев) шума, которые будут наложены. Второй и последующие аргументы задают позицию X, Y, ширину и высоту отображаемой области объекта.
Ускоряем детализацию: noiseWarpDetailPower
Второй объект шума демонстрирует воздействие параметра noiseWarpDetailPower. Этот параметр контролирует, насколько быстро увеличивается детализация (частота) с каждой последующей октавой искажения.
this.noise2 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2,
noiseWarpDetailPower: 4 // Увеличиваем детализацию быстрее.
}, width * 3 / 8, height / 2, width / 4, height);
Чем выше значение noiseWarpDetailPower, тем более "колючим" и высокочастотным становится шум с каждым новым слоем. Это полезно для имитации сложных, изрезанных поверхностей вроде скал или коры дерева.
Контролируем вклад октав: noiseWarpContributionPower
Третий объект использует noiseWarpContributionPower. Этот параметр влияет на то, как быстро уменьшается амплитуда (вклад) каждой последующей октавы в общий результат.
this.noise3 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2,
noiseWarpContributionPower: 1 // Последующие октавы затухают медленнее.
}, width * 5 / 8, height / 2, width / 4, height);
Значение 1 (меньше стандартного) означает более медленное затухание. В результате высокочастотные октавы вносят больший вклад, создавая более "зернистую" и контрастную текстуру с выраженными мелкими деталями.
Запускаем поток: noiseWarpFlowPower
Четвертый объект настраивается через noiseWarpFlowPower. Этот параметр определяет, насколько меняется смещение (noiseFlow) для каждой последующей октавы искажения.
this.noise4 = this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2,
noiseWarpFlowPower: 8 // Последующие октавы "текут" быстрее.
}, width * 7 / 8, height / 2, width / 4, height);
Высокое значение noiseWarpFlowPower приводит к тому, что каждая следующая октава сдвигается с большей скоростью относительно базовой. В анимированном виде (см. update) это создает эффект сложного, многослойного и гипнотического движения, идеального для магических барьеров, тумана или подводных течений.
Анимация через свойство noiseFlow
Динамика — это жизнь. В методе update мы анимируем все четыре текстуры, плавно изменяя их свойство noiseFlow. Это свойство сдвигает координаты выборки шума, создавая иллюзию плавного движения паттерна.
update (time)
{
const t = (time / 1000) % (Math.PI * 2);
this.noise1.noiseFlow = t;
this.noise2.noiseFlow = t;
this.noise3.noiseFlow = t;
this.noise4.noiseFlow = t;
}
Мы берем время в миллисекундах, преобразуем его в секунды и ограничиваем диапазон циклической функцией. Полученное значение `t` плавно нарастает от 0 до ~6.28 и сбрасывается, обеспечивая бесшовную циклическую анимацию для каждого объекта шума.
Что попробовать дальше
Параметры искажения в add.noisesimplex2d — это тонкие кисти для скульптурирования процедурных текстур. Комбинируя noiseWarpDetailPower, noiseWarpContributionPower и noiseWarpFlowPower, вы получаете прямой контроль над детализацией, контрастом и динамикой шума. Для экспериментов попробуйте
- Создать текстуру планеты, комбинируя разные значения
DetailPowerдля материков и океанов - Анимировать
noiseWarpAmountво времени для эффекта "нарастания" или "успокоения" энергии - Использовать шум в качестве маски для цвета или альфа-канала частиц, чтобы создать сложные динамические эффекты
