О чем этот пример
Генерация процедурного контента — ключевой навык в геймдеве. Шум Перлина и симплекс-шум часто используются для создания текстур, ландшафтов, облаков и других органичных форм. В Phaser есть встроенный Game Object `noisesimplex2d`, который визуализирует 2D симплекс-шум. Один из самых мощных параметров этого объекта — `noiseIterations` (количество итераций). Изменяя его, вы контролируете уровень детализации и сложность получаемой карты шума. Эта статья на практическом примере покажет, как `noiseIterations` превращает простой узор в богатую, многослойную текстуру, готовую для использования в вашей игре.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
create()
{
const { width, height } = this.scale;
this.add.noisesimplex2d({
noiseCells: [ 4, 9 ]
}, width * 1 / 8, height / 2, width / 4, height);
this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseIterations: 2
}, width * 3 / 8, height / 2, width / 4, height);
this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseIterations: 3
}, width * 5 / 8, height / 2, width / 4, height);
this.add.noisesimplex2d({
noiseCells: [ 4, 9 ],
noiseIterations: 4
}, width * 7 / 8, height / 2, width / 4, height);
this.add.text(10, 10, '1 iteration', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width / 4 + 10, 10, '2 iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width / 2 + 10, 10, '3 iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width * 3 / 4 + 10, 10, '4 iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1280,
height: 720,
scene: Example
};
const game = new Phaser.Game(config);
Базовое создание симплекс-шума
В Phaser для добавления 2D симплекс-шума на сцену используется метод this.add.noisesimplex2d(). Этот метод принимает объект конфигурации и параметры позиционирования.
Основные параметры конфигурации из нашего примера:
* noiseCells: определяет "крупность" базового узора. Это массив из двух чисел, например [4, 9].
* noiseIterations: количество накладываемых друг на друга слоёв (октав) шума. Чем больше итераций, тем детальнее результат.
Параметры позиционирования (x, y, width, height) задают положение и размер визуализируемого прямоугольника шума на экране.
Вот как создаётся самый простой шум с одной итерацией:
this.add.noisesimplex2d({
noiseCells: [ 4, 9 ]
}, width * 1 / 8, height / 2, width / 4, height);
Магия параметра noiseIterations
Параметр noiseIterations управляет процессом фрактального шума. По умолчанию он равен 1, что даёт простой, плавный градиент.
Когда вы устанавливаете noiseIterations: 2, система генерирует второй слой шума. Этот слой имеет вдвое большую частоту (более мелкие детали) и вдвое меньшую амплитуду (вносит меньший вклад в итоговое значение). Затем он накладывается на первый слой.
Каждая последующая итерация добавляет новый слой с ещё более высокой частотой и ещё меньшей амплитудой. Это создаёт эффект накопления деталей — от крупных форм к мелким.
Код ниже создаёт четыре визуализации с разным количеством итераций, располагая их рядом для сравнения:
this.add.noisesimplex2d({ noiseCells: [ 4, 9 ] }, width * 1 / 8, height / 2, width / 4, height);
this.add.noisesimplex2d({ noiseCells: [ 4, 9 ], noiseIterations: 2 }, width * 3 / 8, height / 2, width / 4, height);
this.add.noisesimplex2d({ noiseCells: [ 4, 9 ], noiseIterations: 3 }, width * 5 / 8, height / 2, width / 4, height);
this.add.noisesimplex2d({ noiseCells: [ 4, 9 ], noiseIterations: 4 }, width * 7 / 8, height / 2, width / 4, height);
Визуализация и подписи
Чтобы сделать пример наглядным, рядом с каждой визуализацией шума добавляется текстовая метка. Для создания текста используется this.add.text().
Метод принимает координаты (x, y), строку с текстом и объект стиля. В примере задан только fontSize. После создания текстового объекта к нему применяются методы для улучшения визуального вида: setStroke() добавляет контур, а setShadow() — тень, что делает текст читаемым на любом фоне.
Расположение текста жёстко привязано к долям ширины экрана (width / 4 + 10, width / 2 + 10 и т.д.), что обеспечивает его корректное отображение рядом с соответствующим блоком шума.
this.add.text(10, 10, '1 iteration', { fontSize: 24 })
.setStroke('#ff8844', 2)
.setShadow(2, 2, '#333333', 2, true, false);
Конфигурация игры и сцены
Пример построен по классической для Phaser схеме. Создаётся класс сцены Example, который расширяет Phaser.Scene. Вся логика отрисовки находится в его методе create().
Затем определяется объект config — конфигурация игры. Ключевые параметры:
* type: Phaser.WEBGL: использует WebGL-рендерер, который необходим для отрисовки шума.
* parent: ID HTML-элемента, в который будет встроен canvas.
* width и height: размеры canvas.
* scene: класс, который будет использоваться в качестве основной сцены.
Финальный шаг — инстанциирование игры с этой конфигурацией.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1280,
height: 720,
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Параметр noiseIterations — это мощный рычаг для управления сложностью процедурного контента. Всего несколько строк кода позволяют получить спектр текстур — от плавных градиентов для фона до детализированных карт высот для террейна.
Идеи для экспериментов:
1. Свяжите значение noiseIterations со временем или действиями игрока для анимированного "проявления" деталей в текстуре.
2. Используйте шум с большим количеством итераций (5-6) в качестве карты высот для генерации островов с реалистичной береговой линией.
3. Поэкспериментируйте с другими параметрами noisesimplex2d, например, noiseScale или colors, чтобы создавать разноцветные облака, лаву или магические поля.
