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

В процессе разработки игры часто возникают ситуации, когда стандартных ассетов из загруженных изображений недостаточно. Например, вам нужно динамически создавать полосы здоровья, индикаторы загрузки или фоны для диалоговых окон прямо во время выполнения игры. Загружать отдельную картинку для каждого такого элемента — неэффективно. Phaser предоставляет мощный инструмент для решения этой задачи: генерацию текстур из графических объектов (`Graphics`). Это позволяет создавать легковесные, программно определяемые текстуры прямо в памяти, что экономит ресурсы и даёт гибкость в прототипировании и создании динамического контента.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.make.graphics().fillStyle(0x00ff00).fillRect(0, 0, 800, 100);

        graphics.generateTexture('hudbar', 800, 100);

        graphics.destroy();

        this.add.image(400, 300, 'hudbar');
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Как это работает: от Graphics к Texture

Ключевой объект в этом процессе — Phaser.GameObjects.Graphics. Это программный холст, на котором можно рисовать примитивы: прямоугольники, круги, линии. После того как нужная форма нарисована, её можно "запечь" в текстуру.

Весь процесс состоит из трёх шагов: 1. Создание и отрисовка графического объекта. 2. Генерация текстуры из этого объекта с присвоением уникального ключа. 3. Уничтожение временного графического объекта и использование новой текстуры как обычного изображения.

Давайте разберём это на примере создания простой горизонтальной полосы (HUD bar).

Разбор примера кода

Всё действие происходит внутри метода create() сцены. Сначала создаётся графический объект.

const graphics = this.make.graphics().fillStyle(0x00ff00).fillRect(0, 0, 800, 100);

Здесь this.make.graphics() создаёт новый объект Graphics. Метод fillStyle(0x00ff00) задаёт цвет заливки (ярко-зелёный). fillRect(0, 0, 800, 100) рисует залитый прямоугольник шириной 800 пикселей и высотой 100 пикселей.

Далее происходит самая важная операция — генерация текстуры.

graphics.generateTexture('hudbar', 800, 100);

Метод generateTexture() принимает три аргумента: ключ текстуры ('hudbar'), её ширину и высоту. Phaser берёт текущее содержимое объекта graphics в указанных границах и создаёт из него новую текстуру, которая автоматически добавляется в текстовый кеш игры под переданным ключом.

После этого временный объект graphics больше не нужен, и его можно уничтожить, чтобы освободить ресурсы.

graphics.destroy();

Теперь сгенерированную текстуру можно использовать как любую другую, загруженную из файла.

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

Здесь создаётся игровой объект Image, который использует текстуру с ключом 'hudbar' и помещает его в центр сцены (координаты 400, 300).

Практические применения и преимущества

Этот подход невероятно полезен в реальной разработке:

* **Динамические UI-элементы:** Полосы здоровья и маны, которые меняют ширину, индикаторы прогресса, кастомные рамки для кнопок. * **Процедурная генерация:** Создание уникального фона для карты, простых тайлов или эффектов непосредственно в игре. * **Оптимизация:** Вы избегаете лишних HTTP-запросов на загрузку мелких UI-элементов, уменьшаете размер итогового билда игры. * **Прототипирование:** Быстрое создание placeholder-графики для тестирования геймплея без привлечения художника.

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

Важные нюансы и ограничения

При работе с generateTexture() стоит помнить о нескольких моментах:

1. **Уникальность ключа:** Ключ текстуры (первый аргумент) должен быть уникальным. Попытка создать текстуру с ключом, который уже существует в кеше, перезапишет старую текстуру. 2. **Размеры:** Указанные ширину и высоту (800, 100) стоит точно соответствовать размеру нарисованной области в Graphics. Если указать бóльшие размеры, вокруг вашего рисунка появятся прозрачные области. Если меньшие — рисунок будет обрезан. 3. **Производительность:** Генерация текстуры — операция, требующая вычислений. Её не стоит выполнять каждый кадр. Стандартный паттерн — создать набор необходимых текстур один раз при инициализации сцены (create) или объекта. 4. **Сложная графика:** Graphics отлично подходит для примитивов. Для создания сложных, многослойных или анимированных текстур на лету лучше рассмотреть использование Render Textures (this.add.renderTexture).

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

Генерация текстур из объектов Graphics — это мощный и элегантный способ добавить динамичности и гибкости вашему игровому интерфейсу, избегая лишних статических ассетов. Этот метод отлично подходит для создания простых, программно управляемых визуальных элементов. **Идеи для экспериментов:** Попробуйте создать не просто прямоугольник, а текстуру с закруглёнными краями, используя fillRoundedRect. Сгенерируйте градиентную полосу, нарисовав несколько прямоугольников с разным цветом рядом. Или создайте текстуру для уникального курсора мыши, нарисовав крестик или прицел с помощью lineBetween.