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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    graphics;
    rt;

    create ()
    {
        this.graphics = this.add.graphics();
        this.graphics.setVisible(false);

        this.drawStar(this.graphics, 200, 200, 5, 200, 100, 0xffff00);

        this.rt = this.add.renderTexture(400, 300, 400, 400).setOrigin(0.5);
    }

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

        this.rt.clear();

        this.rt.draw(this.graphics);

        this.rt.render();
    }

    drawStar (graphics, cx, cy, spikes, outerRadius, innerRadius, color)
    {
        let rot = Math.PI / 2 * 3;
        let x = cx;
        let y = cy;
        const step = Math.PI / spikes;

        graphics.fillStyle(color, 1.0);
        graphics.beginPath();
        graphics.moveTo(cx, cy - outerRadius);

        for (let i = 0; i < spikes; i++)
        {
            x = cx + Math.cos(rot) * outerRadius;
            y = cy + Math.sin(rot) * outerRadius;
            graphics.lineTo(x, y);
            rot += step;

            x = cx + Math.cos(rot) * innerRadius;
            y = cy + Math.sin(rot) * innerRadius;
            graphics.lineTo(x, y);
            rot += step;
        }

        graphics.lineTo(cx, cy - outerRadius);
        graphics.closePath();
        graphics.fillPath();
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и создание объектов

В методе create() инициализируются два ключевых объекта: Graphics и Render Texture.

Объект Graphics — это инструмент для векторного рисования. Мы создаем его, но сразу делаем невидимым, так как он будет служить лишь шаблоном или «кистью» для отрисовки.

this.graphics = this.add.graphics();
this.graphics.setVisible(false);

Затем с помощью вспомогательного метода drawStar на объекте graphics рисуется желтая пятиконечная звезда. Ее координаты (200, 200) задаются относительно самого объекта Graphics, а не сцены.

Следующим шагом создается сама Render Texture. Это специальный игровой объект, который представляет собой область в памяти (холст) для рендеринга.

this.rt = this.add.renderTexture(400, 300, 400, 400).setOrigin(0.5);

Здесь мы создаем текстуру размером 400x400 пикселей, позиционируем ее в центре сцены (400, 300) и устанавливаем точку вращения (origin) в ее центр.

Цикл обновления: анимация через управление камерой

Вся магия происходит в методе update(), который выполняется каждый кадр. Ключевой момент: у Render Texture есть своя собственная камера (this.rt.camera). Вращая эту камеру, мы меняем «точку обзора» на содержимое текстуры, что создает эффект вращения самой отрисованной графики.

this.rt.camera.rotation -= 0.01;

Перед тем как что-то нарисовать заново, необходимо очистить текстуру от содержимого предыдущего кадра. Для этого используется метод .clear().

this.rt.clear();

Рисование и финальный рендер

После очистки мы «штампуем» нашу заранее нарисованную звезду (объект graphics) на холст Render Texture. Важно понимать: мы рисуем не сам объект Graphics, а его визуальное представление (то, что было нарисовано в нем методами fillStyle, beginPath и т.д.).

this.rt.draw(this.graphics);

Метод draw() может принимать не только Graphics, но и другие объекты, например, спрайты или тексты.

Финальный шаг — вызов .render(). Этот метод явно указывает движку, что все операции отрисовки для данной текстуры завершены и ее нужно визуализировать. Без этого вызова изменения могут не отобразиться на экране.

this.rt.render();

Таким образом, каждый кадр мы: 1) поворачиваем камеру текстуры, 2) очищаем ее, 3) рисуем звезду в новом положении камеры и 4) выводим результат на экран.

Вспомогательная функция drawStar

Это классическая функция для рисования звезды с использованием тригонометрии. Она работает непосредственно с API объекта Graphics.

- cx, cy: центральная точка звезды. - spikes: количество лучей. - outerRadius, innerRadius: радиусы вершин и впадин лучей. - color: цвет заливки.

Функция последовательно вычисляет точки луча звезды, используя Math.cos и Math.sin, и соединяет их линиями, формируя путь (path), который затем заливается цветом.

graphics.fillStyle(color, 1.0);
graphics.beginPath();
graphics.moveTo(cx, cy - outerRadius);
// ... вычисление и отрисовка точек
 graphics.closePath();
graphics.fillPath();

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

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

  1. рисовать в текстуру несколько разных объектов Graphics
  2. анимировать не только вращение камеры, но и ее масштаб (this.rt.camera.zoom)
  3. использовать this.rt.saveTexture('key') для сохранения результата рендера в текстуру кэша и последующего применения к спрайту