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

Работа с динамическими текстурами — мощный инструмент в арсенале разработчика игр. Класс `RenderTexture` в Phaser позволяет создавать и манипулировать графикой в реальном времени, что открывает возможности для создания спецэффектов, интерфейсов или оптимизации отрисовки сложных сцен. В этой статье мы разберем базовый пример использования `RenderTexture` для рисования изображений на собственном холсте, что станет основой для более продвинутых техник.

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

Живой запуск

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

Исходный код


var config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    width: 1200,
    height: 600,
    backgroundColor: '#2d2d88',
    scene: {
        preload: preload,
        create: create
    }
};

var game = new Phaser.Game(config);

function preload ()
{
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('bg', 'assets/pics/purple-dots.png');
    this.load.image('nayuki', 'assets/pics/nayuki.png');
}

function create ()
{
    var bob = this.make.image({ key: 'nayuki' }, false).setOrigin(0, 0);

    // var rt = this.add.renderTexture(400, 300, 800, 600).setOrigin(0.5, 0.5);
    var rt = this.add.renderTexture(0, 0, 800, 600);

    // rt.draw('bg', 0, 0);

    // rt.drawFrame('nayuki');

    rt.draw(bob, 0, 0);

    // this.add.image(0, 0, 'nayuki').setOrigin(0, 0);

    // var b = this.add.image(0, 0, 'bg').setOrigin(0, 0).setAlpha(1);

    // this.input.on('pointerdown', () => {

    //     b.visible = !b.visible;

    // });


}

Что такое RenderTexture?

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

Созданная текстура затем может быть использована как источник для отображения, например, будучи добавленной на сцену через this.add.image или как текстура для спрайта. Основное преимущество — возможность один раз отрисовать сложную композицию из множества объектов и затем отображать ее как единое целое, что может повысить производительность.

Настройка сцены и загрузка ассетов

Первым делом настраивается конфигурация игры и загружаются изображения. Обратите внимание, что в этом примере используется рендерер Phaser.CANVAS. Работа RenderTexture может отличаться в WebGL-режиме.

var config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    width: 1200,
    height: 600,
    backgroundColor: '#2d2d88',
    scene: {
        preload: preload,
        create: create
    }
};

var game = new Phaser.Game(config);

В функции preload задается базовый URL и загружаются два изображения: фоновое (bg) и основное (nayuki).

function preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('bg', 'assets/pics/purple-dots.png');
    this.load.image('nayuki', 'assets/pics/nayuki.png');
}

Создание RenderTexture и отрисовка в нее

В функции create происходит основная магия. Сначала создается игровой объект Image из загруженной текстуры nayuki. Метод this.make.image создает объект, но не добавляет его сразу на сцену для отображения. Это полезно, когда объект нужен только как источник для рисования.

var bob = this.make.image({ key: 'nayuki' }, false).setOrigin(0, 0);

Далее создается сама RenderTexture с размерами 800x600 пикселей и позицией (0, 0) на сцене.

var rt = this.add.renderTexture(0, 0, 800, 600);

Ключевой шаг — использование метода draw для переноса содержимого изображения bob на холст RenderTexture. Первые два аргумента — это объект для рисования и его координаты *внутри* текстуры.

rt.draw(bob, 0, 0);

После этого вызова rt содержит изображение Наюки, нарисованное в его левом верхнем углу. Поскольку rt был добавлен на сцену через this.add.renderTexture, он автоматически отображается.

Почему это работает именно так?

Важно понимать порядок и результат операций: 1. Объект bob существует в памяти, но не отрисовывается на игровом холсте сцены самостоятельно. 2. RenderTexture (rt) является отображаемым игровым объектом (наследником GameObject). Он добавляется на сцену и рендерится. 3. Метод draw выполняет операцию копирования пикселей (или векторной команды) из источника (bob) во внутренний буфер rt. 4. В итоге на экране мы видим не оригинальное изображение nayuki, а его "отпечаток" на поверхности RenderTexture.

Это позволяет, например, один раз нарисовать статический сложный UI в RenderTexture и затем не тратить ресурсы на перерисовку каждого его элемента каждый кадр. Также можно применять фильтры или трансформации ко всей текстуре целиком.

Комментированный код и эксперименты

В исходном примере много закомментированных строк. Это намекает на возможности для экспериментов. Давайте их активируем по очереди, чтобы понять логику.

Если создать RenderTexture с центром в координатах (400, 300), изображение в ней будет позиционироваться относительно этого центра.

// var rt = this.add.renderTexture(400, 300, 800, 600).setOrigin(0.5, 0.5);

Метод draw может принимать не только игровые объекты, но и ключ текстуры или даже имя кадра из атласа.

// rt.draw('bg', 0, 0); // Нарисовать фоновое изображение по ключу
// rt.drawFrame('nayuki'); // Альтернативный метод рисования кадра

Вы можете добавить оригинальное изображение на сцену для сравнения:

// this.add.image(0, 0, 'nayuki').setOrigin(0, 0);

А этот блок кода добавляет переключатель видимости фона, что полезно для отладки и понимания слоев.

// var b = this.add.image(0, 0, 'bg').setOrigin(0, 0).setAlpha(1);
// this.input.on('pointerdown', () => {
//     b.visible = !b.visible;
// });

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

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