Процедурная генерация текстур

Процедурная генерация текстур в Phaser позволяет создавать динамические графические элементы во время выполнения игры без необходимости хранить их в виде файлов. Это особенно полезно для спрайтов, фонов, частиц, тайловых карт и UI-элементов, когда требуется разнообразие или экономия памяти.

В Phaser 3 основной инструмент для таких задач — объект Graphics и методы класса TextureManager, который управляет текстурами.

Использование Graphics для генерации текстур

Phaser.GameObjects.Graphics позволяет рисовать примитивы (прямоугольники, окружности, линии, полигоны) и сохранять их в текстуры.

Пример базового подхода:

const graphics = this.add.graphics();

// Настройка заливки и линии
graphics.fillStyle(0xff0000, 1); // красная заливка
graphics.lineStyle(2, 0x000000, 1); // черная линия

// Рисование прямоугольника
graphics.strokeRect(50, 50, 100, 100);
graphics.fillRect(50, 50, 100, 100);

// Сохранение графики в текстуру
graphics.generateTexture('redBox', 200, 200);
graphics.destroy(); // после генерации можно удалить объект

Ключевой момент: метод generateTexture создает имя текстуры, которую можно использовать как обычный спрайт:

this.add.image(400, 300, 'redBox');

Это позволяет создавать текстуры динамически, в зависимости от игровых условий.

Генерация случайных и вариативных текстур

Процедурная генерация раскрывается, когда используется случайная генерация. Для имитации естественных объектов (камни, травинка, облака) применяют методы случайного распределения и шумовые алгоритмы.

Пример создания текстуры с шумом:

const width = 128;
const height = 128;
const graphics = this.add.graphics();

for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
        const value = Math.floor(Math.random() * 256);
        graphics.fillStyle((value << 16) | (value << 8) | value, 1);
        graphics.fillRect(x, y, 1, 1);
    }
}

graphics.generateTexture('noise', width, height);
graphics.destroy();

В результате получается текстура, где каждый пиксель имеет случайный оттенок серого. Это базовый пример пиксельного шума, который можно использовать для создания эффекта дыма, воды или текстурной подложки.

Использование Canvas для сложных процедурных эффектов

Иногда Graphics не подходит для сложных вычислительных операций на пикселях, например для фильтров или генерации градиентов с искажениями. В этом случае используют CanvasTexture.

const texture = this.textures.createCanvas('gradient', 256, 256);
const ctx = texture.getContext();

const gradient = ctx.createLinearGradient(0, 0, 256, 256);
gradient.addColorStop(0, '#ff0000');
gradient.addColorStop(1, '#0000ff');

ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 256, 256);

texture.refresh(); // обновление текстуры для использования в спрайте

this.add.image(400, 300, 'gradient');

CanvasTexture позволяет использовать весь API HTML5 Canvas, включая кривые Безье, фильтры, градиенты и пиксельные манипуляции, что делает возможным генерацию сложных текстур, аналогичных программной графике.

Анимация процедурных текстур

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

const texture = this.textures.createCanvas('animatedNoise', 128, 128);
const ctx = texture.getContext();

this.time.addEvent({
    delay: 50,
    loop: true,
    callback: () => {
        for (let x = 0; x < 128; x++) {
            for (let y = 0; y < 128; y++) {
                const value = Math.floor(Math.random() * 256);
                ctx.fillStyle = `rgb(${value},${value},${value})`;
                ctx.fillRect(x, y, 1, 1);
            }
        }
        texture.refresh();
    }
});

Такой подход используется для создания эффекта огня, дыма, искр или воды. Основной принцип: каждое обновление CanvasTexture сопровождается вызовом refresh().

Оптимизация процедурной генерации

  1. Использование меньших размеров текстур — особенно для тайлов и частиц. Большие текстуры требуют больше видеопамяти.
  2. Пересоздание только измененных областей — метод drawImage и CanvasRenderingContext2D.putImageData позволяют обновлять части текстуры, что ускоряет работу.
  3. Кэширование процедурных текстур — если текстура может повторяться, лучше создать её один раз и повторно использовать, вместо генерации каждый кадр.
  4. Комбинирование Graphics и CanvasTexture — Graphics удобен для геометрических фигур, CanvasTexture — для пиксельных эффектов и фильтров.

Практические сценарии применения

  • Фоновые текстуры — Procedural sky, clouds, water, terrain.
  • Частицы — дым, огонь, искры, брызги.
  • Спрайты персонажей и объектов — случайные вариации брони, оружия, еды.
  • UI и элементы интерфейса — динамические кнопки, индикаторы, градиенты.

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