О чем этот пример
Работа с графикой — ключевая часть разработки игр. Часто возникает необходимость создавать текстуры на лету, комбинируя несколько элементов, и затем использовать их как обычные спрайты. В Phaser для этого идеально подходит `Render Texture`. Эта статья покажет, как создать составную текстуру из примитива и изображения, сохранить её в кэш текстур и мгновенно генерировать десятки её копий, что особенно полезно для создания частиц, фоновых элементов или сложных составных объектов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
bubbles = [];
rt;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('dude', 'assets/sprites/phaser-dude.png');
}
create ()
{
this.rt = this.add.renderTexture(40, 40, 80, 80);
const circle = this.add.circle(0, 0, 40, 0x6666ff).setAlpha(0.5).setVisible(false);
this.rt.draw(circle, 40, 40);
this.rt.draw('dude', 40, 40);
this.rt.render();
this.rt.saveTexture('bubbleboy');
for (let i = 0; i < 50; i++)
{
const b = this.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(100, 500), 'bubbleboy');
this.bubbles.push(b);
}
this.input.on('pointerup', () =>
{
game.destroy(true);
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d88',
scene: Example
};
const game = new Phaser.Game(config);
Что такое Render Texture и зачем она нужна
Render Texture (текстура отрисовки) — это специальный игровой объект в Phaser, который работает как холст. Вы можете отрисовывать на нём другие игровые объекты (спрайты, графику, текст), а результат будет представлять собой единое растровое изображение.
Основное преимущество — производительность. Если вам нужно множество одинаковых составных объектов (например, спрайт с нимбом или надписью), эффективнее один раз отрисовать эту композицию в Render Texture, сохранить её как текстуру, а затем создавать стандартные Image объекты из неё. Это снижает количество операций отрисовки (draw calls) на каждом кадре.
В нашем примере мы создадим текстуру, состоящую из полупрозрачного синего круга и спрайта "Phaser Dude" поверх него.
Инициализация и настройка сцены
Всё начинается с конфигурации игры и создания сцены. Класс Example расширяет Phaser.Scene.
В методе preload() загружается единственный внешний ресурс — спрайт. Обратите внимание, что setBaseURL задаёт базовый путь для удобства.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('dude', 'assets/sprites/phaser-dude.png');
}
Конфиг игры задаёт основные параметры: тип рендерера, родительский DOM-элемент, размеры окна и цвет фона. Важно, что в свойстве scene передаётся класс нашей сцены.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d88',
scene: Example
};
const game = new Phaser.Game(config);
Создание и наполнение Render Texture
Основная магия происходит в методе create(). Первым делом создаётся сам объект Render Texture с помощью this.add.renderTexture(x, y, width, height). Он позиционируется на сцене, но в данном примере это не важно, так как он служит лишь промежуточным холстом.
this.rt = this.add.renderTexture(40, 40, 80, 80);
Далее создаётся графический примитив — круг. Ключевые моменты:
- setAlpha(0.5) делает его полупрозрачным.
- setVisible(false) скрывает его как самостоятельный объект на сцене, потому что нам нужен только его отпечаток на текстуре.
const circle = this.add.circle(0, 0, 40, 0x6666ff).setAlpha(0.5).setVisible(false);
Метод draw() объекта rt помещает указанный объект (или текстуру по ключу) в его буфер отрисовки по заданным координатам. Координаты (40, 40) здесь — это центр нашей Render Texture размером 80x80 пикселей.
this.rt.draw(circle, 40, 40);
this.rt.draw('dude', 40, 40);
После того как все элементы отрисованы, вызывается this.rt.render(). Этот метод финализирует отрисовку на внутреннем холсте текстуры. Следующий шаг — сохранение результата в глобальный кэш текстур игры с помощью saveTexture(). Теперь к текстуре можно обращаться по ключу 'bubbleboy', как к любой загруженной картинке.
this.rt.render();
this.rt.saveTexture('bubbleboy');
Массовое создание объектов из новой текстуры
После того как текстура 'bubbleboy' сохранена, её можно использовать бесконечное количество раз. В цикле создаётся 50 стандартных объектов Image. Каждый из них использует нашу новую, динамически созданную текстуру.
Phaser.Math.Between задаёт случайные координаты для каждого спрайта в пределах игрового поля. Все созданные объекты сохраняются в массив bubbles (хотя в данном примере он далее не используется).
for (let i = 0; i < 50; i++)
{
const b = this.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(100, 500), 'bubbleboy');
this.bubbles.push(b);
}
Финальный обработчик события pointerup демонстрирует, как можно полностью уничтожить экземпляр игры.
this.input.on('pointerup', () =>
{
game.destroy(true);
});
Что попробовать дальше
Render Texture — это мощный инструмент для динамической генерации графики в Phaser. Он позволяет комбинировать различные элементы в единую текстуру, которую затем можно использовать для оптимизации или создания сложных визуальных эффектов. Для экспериментов попробуйте: анимировать элементы перед отрисовкой на текстуру, использовать Render Texture для создания мини-карты (мапы), менять свойства (например, tint) уже созданных объектов 'bubbleboy' или реализовать систему следов/отпечатков, рисуя на одной Render Texture каждый кадр.
