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

При создании игр часто возникает задача отрисовки множества спрайтов из одного набора изображений (атласа). Если эти спрайты статичны, их постоянное обновление через физику или систему отображения — пустая трата ресурсов. Render Texture позволяет "запечь" множество кадров в одну текстуру, превратив её в единый игровой объект. Это оптимизирует производительность, особенно для фонов, сложных статичных сцен или UI-элементов, собранных из множества мелких частей.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.atlas('megaset', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');
    }

    create ()
    {
        const rt = this.add.renderTexture(400, 300, 800, 600);

        const atlasTexture = this.textures.get('megaset');

        const frames = atlasTexture.getFrameNames();

        for (let i = 0; i < frames.length; i++)
        {
            const x = Phaser.Math.Between(0, 800);
            const y = Phaser.Math.Between(0, 600);

            rt.stamp('megaset', frames[i], x, y);
        }

        rt.render();
    }
}

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

const game = new Phaser.Game(config);

Что такое Render Texture?

RenderTexture — это особый тип объекта в Phaser, который представляет собой холст в памяти. Вы можете рисовать на нём другие игровые объекты, текстуры или кадры из атласа. После завершения отрисовки Render Texture становится единым изображением (текстурой), которое можно отобразить на сцене как обычный спрайт.

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

В нашем примере мы создадим такую текстуру и наполним её случайными кадрами из загруженного атласа.

Подготовка: загрузка атласа и создание холста

Всё начинается с загрузки ресурсов. Мы используем текстуру-атлас megaset, который содержит множество отдельных изображений (кадров) в одном файле.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('megaset', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');

В методе create() мы создаём экземпляр RenderTexture. Параметры конструктора — координаты центра (x, y), ширина и высота текстуры в пикселях.

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

Теперь у нас есть пустой холст размером 800x600, размещённый в центре сцены. Далее мы получим ссылку на саму текстуру атласа и извлечём из неё список имён всех доступных кадров.

const atlasTexture = this.textures.get('megaset');
const frames = atlasTexture.getFrameNames();

Массив frames теперь содержит строковые идентификаторы каждого изображения в атласе.

Пакетная отрисовка методом stamp

Основной инструмент для наполнения Render Texture — метод .stamp(). Он "штампует" заданный кадр из текстуры в указанные координаты на холсте.

В нашем примере мы проходим по всем именам кадров в цикле. Для каждого кадра генерируются случайные координаты в пределах размеров нашей Render Texture.

for (let i = 0; i < frames.length; i++)
{
    const x = Phaser.Math.Between(0, 800);
    const y = Phaser.Math.Between(0, 600);
    rt.stamp('megaset', frames[i], x, y);
}

Важно понимать, что stamp принимает: 1. Ключ текстуры ('megaset'). 2. Имя кадра из этой текстуры (например, 'aya', 'platform'). 3. Координаты X и Y для отрисовки на самом холсте Render Texture.

На этом этапе все операции происходят в памяти. На экране пока ничего не изменилось.

Финализация: метод render

После того как все нужные элементы отрисованы методом stamp, необходимо зафиксировать результат. Для этого вызывается метод .render().

rt.render();

Этот метод сообщает Render Texture, что процесс пакетной отрисовки завершён. Текстура финализируется и отправляется на отрисовку на экран как единый объект. Без вызова render() созданный нами холст останется пустым и невидимым.

Теперь на сцене отображается одно изображение (наша Render Texture), содержащее в себе все разбросанные кадры из атласа. Движок больше не отслеживает их как отдельные сущности.

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

Render Texture — мощный инструмент для оптимизации статичного контента. Вы "запекаете" сложную композицию один раз, а затем используете её как простой спрайт. Идеи для экспериментов: 1. Используйте rt.draw() для отрисовки целых игровых объектов (например, спрайтов с уже применёнными эффектами) на ваш холст. 2. Создайте сложный статичный фон уровня, скомбинировав тайлы и декоративные элементы в одну текстуру. 3. Реализуйте систему следов или временных эффектов, рисуя их на Render Texture с полупрозрачностью, а затем постепенно её уменьшая. 4. Поэкспериментируйте с методами rt.clear() для стирания части холста и rt.saveTexture() для получения ключа созданной текстуры и её повторного использования в других местах игры.