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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    particles;
    rt;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
    }

    create ()
    {
        this.particles = this.add.particles(0, 0, 'flares', {
            frame: 'blue',
            x: 400,
            y: 300,
            lifespan: 2000,
            speed: { min: 400, max: 600 },
            angle: 0,
            gravityY: 300,
            scale: { start: 0.4, end: 0 },
            quantity: 2,
            blendMode: 'ADD'
        });

        this.particles.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.particles, 0, 0);

        this.rt.render();
    }
}

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

const game = new Phaser.Game(config);

Инициализация сцены и загрузка ресурсов

Начнём с базовой структуры сцены и загрузки атласа для системы частиц. Атлас flares содержит спрайты, которые будут использоваться как частицы. Мы устанавливаем базовый URL для загрузчика.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
}

Создание системы частиц и Render Texture

В методе create() создаются два ключевых объекта: эмиттер частиц и Render Texture. Эмиттер настраивается для генерации синих частиц (frame: 'blue') с заданными параметрами скорости, гравитации и масштаба. Частицы будут вылетать из точки (400, 300) с разбросом скорости и падать под действием гравитации (gravityY: 300). Ключевой момент: частицы сразу же скрываются методом setVisible(false), так как они будут отрисовываться не напрямую на сцену, а в текстуру.

this.particles = this.add.particles(0, 0, 'flares', {
    frame: 'blue',
    x: 400,
    y: 300,
    lifespan: 2000,
    speed: { min: 400, max: 600 },
    angle: 0,
    gravityY: 300,
    scale: { start: 0.4, end: 0 },
    quantity: 2,
    blendMode: 'ADD'
});

this.particles.setVisible(false);

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

Render Texture создаётся с центром в (400, 300) и размерами 800x600, что соответствует размеру игрового окна в этом примере. Он будет служить нашим целевым холстом для рисования.

Динамическое обновление и вращение

Вся магия происходит в методе update(), который вызывается каждый кадр. Здесь мы выполняем три действия: вращаем камеру Render Texture, очищаем текстуру и рисуем в неё текущее состояние системы частиц.

this.rt.camera.rotation -= 0.01;

this.rt.clear();

this.rt.draw(this.particles, 0, 0);

this.rt.render();
1. `this.rt.camera.rotation -= 0.01` — плавно вращает камеру Render Texture против часовой стрелки, что заставляет всё нарисованное в текстуре вращаться.
2. `this.rt.clear()` — очищает текстуру от предыдущего кадра, чтобы избежать накопления старого изображения.
3. `this.rt.draw(this.particles, 0, 0)` — рисует текущие частицы в текстуру. Координаты (0, 0) означают, что частицы рисуются относительно центра текстуры.
4. `this.rt.render()` — явно обновляет текстуру для отображения изменений. Этот вызов необходим, так как мы работаем с текстурой вручную.

Сборка игры и конфигурация

Инициализация игры происходит стандартно. Конфигурация задаёт тип рендерера, элемент-контейнер, размеры окна и класс сцены.

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

const game = new Phaser.Game(config);

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

Render Texture предоставляет гибкий способ для композиции и трансформации визуальных элементов, таких как частицы, в единое целое. В этом примере мы создали вращающийся поток частиц, используя отдельную текстуру. Для экспериментов попробуйте: изменить параметры эмиттера (например, angle или blendMode), добавить несколько Render Texture для многослойных эффектов, рисовать в текстуру другие игровые объекты (спрайты, группы) или применить шейдеры к самой текстуре для цветовой коррекции.