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

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

Версия 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.image('bunny', 'assets/sprites/bunny.png');
    }

    create ()
    {
        const rt1 = this.add.renderTexture(0, 0, 400, 600).setOrigin(0, 0);

        for (let i = 0; i < 16; i++)
        {
            const x = Phaser.Math.Between(-200, 400);
            const y = Phaser.Math.Between(-100, 600);

            rt1.draw('bunny', x, y);
        }

        rt1.render();

        const rt2 = this.add.renderTexture(400, 0, 400, 600).setOrigin(0, 0);

        rt2.draw(rt1, 0, 0).render();
    }
}

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

const game = new Phaser.Game(config);

Что такое Render Texture?

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

Ключевой момент: после добавления объектов в рендер-текстуру с помощью метода draw(), необходимо вызвать метод render(), чтобы зафиксировать все изменения и сделать текстуру видимой.

Создание и наполнение первой текстуры (rt1)

В примере сначала создается рендер-текстура rt1. Она размещается в левой половине экрана (координаты 0,0) и имеет размер 400x600 пикселей.

const rt1 = this.add.renderTexture(0, 0, 400, 600).setOrigin(0, 0);

Затем в цикле метод draw() добавляет 16 случайных спрайтов «bunny» в произвольных позициях внутри области текстуры (и даже за ее пределами, что допустимо).

for (let i = 0; i < 16; i++)
{
    const x = Phaser.Math.Between(-200, 400);
    const y = Phaser.Math.Between(-100, 600);
    rt1.draw('bunny', x, y);
}

После добавления всех спрайтов вызывается rt1.render(). Без этого вызова rt1 останется пустой на экране.

Копирование содержимого в вторую текстуру (rt2)

Далее создается вторая рендер-текстура rt2 в правой половине экрана (координата x=400).

const rt2 = this.add.renderTexture(400, 0, 400, 600).setOrigin(0, 0);

Самая интересная часть кода — отрисовка первой текстуры во вторую. В метод draw() вторым параметром можно передать не только ключ изображения, но и сам игровой объект rt1.

rt2.draw(rt1, 0, 0).render();

Здесь rt1 отрисовывается в rt2 с координатами (0,0). Методы draw() и render() можно вызывать цепочкой. В итоге мы получаем зеркальную копию левой сцены в правой части.

Практическое применение техники

Почему это полезно? Потому что rt1 теперь — это не просто набор спрайтов, а единая текстура. С ней можно делать то, что сложно или накладно делать с отдельными объектами: * **Применение шейдеров/фильтров:** Можно применить фильтр (например, размытие или инверсию цвета) ко всей сцене, нарисованной в rt1, перед отображением в rt2. * **Создание мини-карты:** В rt1 можно нарисовать упрощенное представление уровня, а в rt2 — уменьшенную его копию в углу экрана. * **Динамические маски и порталы:** Содержимое rt1 можно использовать как маску или отображать через другую геометрию. * **Оптимизация:** Сложная статическая сцена, отрендеренная один раз в текстуру, может быть отрисована за один вызов, что иногда эффективнее, чем рендеринг сотен отдельных спрайтов каждый кадр.

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

Работа с рендер-текстурами как с объектами для отрисовки открывает путь к сложным визуальным эффектам и оптимизациям в Phaser. Экспериментируйте: попробуйте применить к rt2 фильтр (Blur, Glow) после копирования rt1. Или создайте цепочку из нескольких текстур, где каждая последующая искажает предыдущую. Можно также рисовать в текстуру не спрайты, а частицы или тайловые слои, создавая уникальные композиции.