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

Render Texture в Phaser 3 — это мощный инструмент для рендеринга игровых объектов в текстуру, с которой затем можно работать как с единым изображением. Это открывает возможности для создания сложных визуальных эффектов, таких как дрожащий текст, частицы или динамические маски, без необходимости обрабатывать каждый объект отдельно на основном канвасе. В этой статье мы разберем практический пример совмещения динамического bitmap-текста с Render Texture для генерации стильного, анимированного заголовка.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    bitmaptext;
    rt;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
    }

    create ()
    {
        this.bitmaptext = this.add.dynamicBitmapText(0, 0, 'desyrel', 'PHASER 3\nRender Texture', 64);

        this.bitmaptext.setDisplayCallback(this.textCallback);

        this.bitmaptext.setVisible(false);

        this.rt = this.add.renderTexture(400, 300, 800, 600);
    }

    update ()
    {
        this.rt.camera.rotation -= 0.01;

        this.rt.clear();

        this.rt.draw(this.bitmaptext, 300, 400);

        this.rt.render();
    }

    textCallback (data)
    {
        data.x = Phaser.Math.Between(data.x - 2, data.x + 2);
        data.y = Phaser.Math.Between(data.y - 4, data.y + 4);

        return data;
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и загрузка ресурсов

В методе preload загружается bitmap-шрифт. Важно указать и изображение, и XML-файл с данными о глифах.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
}

В методе create инициализируются ключевые объекты. Сначала создается динамический bitmap-текст. Его особенность — возможность изменять свойства каждого символа в реальном времени через callback-функцию.

create ()
{
    this.bitmaptext = this.add.dynamicBitmapText(0, 0, 'desyrel', 'PHASER 3\nRender Texture', 64);
    this.bitmaptext.setDisplayCallback(this.textCallback);
    this.bitmaptext.setVisible(false);
    this.rt = this.add.renderTexture(400, 300, 800, 600);
}

Обратите внимание: исходный текст (this.bitmaptext) скрыт методом setVisible(false), потому что он будет отрисовываться не на основную сцену, а внутрь Render Texture.

Магия Render Texture: принцип работы

Render Texture (this.rt) — это, по сути, отдельный канвас или кадровый буфер. В данном примере он создается с центром в точке (400, 300) и размером 800x600 пикселей.

Основная логика анимации происходит в update. Каждый кадр мы: 1. Вращаем камеру самой Render Texture. 2. Очищаем её предыдущее содержимое. 3. Отрисовываем в неё наш динамический текст. 4. Явно вызываем рендеринг.

Этот цикл создает эффект постоянно вращающейся текстуры со статичным относительно неё текстом.

update ()
{
    this.rt.camera.rotation -= 0.01;
    this.rt.clear();
    this.rt.draw(this.bitmaptext, 300, 400);
    this.rt.render();
}

Метод draw принимает игровой объект и координаты для отрисовки внутри Render Texture. Здесь текст рисуется в точке (300, 400) относительно центра rt.

Динамическое изменение текста через Callback

Сила DynamicBitmapText раскрывается в функции обратного вызова textCallback. Она выполняется для каждого символа текста перед его отрисовкой, позволяя модифицировать его свойства.

textCallback (data)
{
    data.x = Phaser.Math.Between(data.x - 2, data.x + 2);
    data.y = Phaser.Math.Between(data.y - 4, data.y + 4);
    return data;
}

Функция получает объект data с параметрами символа (координаты, индекс, код и т.д.). В данном примере мы каждый кадр случайным образом смещаем символ по осям X и Y в небольшом диапазоне, используя Phaser.Math.Between. Это создает эффект легкого, хаотичного дрожания («шума») для каждого символа, что добавляет тексту живого, цифрового вида.

Этот callback назначается тексту с помощью setDisplayCallback(this.textCallback).

Конфигурация игры и запуск

Стандартная конфигурация игры Phaser 3. Ключевой момент — указание нашего класса Example в качестве основной сцены.

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

const game = new Phaser.Game(config);

Размеры окна игры (800x600) соответствуют размеру созданной Render Texture, что позволяет ей заполнить весь экран.

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

Комбинация DynamicBitmapText с Render Texture предоставляет отличный контроль над сложными текстовыми эффектами, изолируя их рендеринг от основного игрового поля. Вы можете экспериментировать: изменять логику в textCallback для масштабирования, окрашивания или поворота символов; анимировать не камеру, а саму Render Texture в пространстве сцены; или рисовать в одну текстуру несколько различных объектов (спрайты, частицы) для создания сложных композитных эффектов.