О чем этот пример
Render Texture — это мощный инструмент в Phaser 3, позволяющий рисовать и комбинировать игровые объекты на лету, создавая эффекты рисования, следы или динамические текстуры. В этой статье мы разберем, как использовать Render Texture для интерактивного рисования выбранным спрайтом по холсту, управляя всем одним указателем мыши. Этот подход открывает двери для создания кастомизируемых кистей, штампов и неразрушающих визуальных эффектов прямо во время игры.
Версия 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.atlas('atlas', 'assets/atlas/megaset-1.png', 'assets/atlas/megaset-1.json');
}
create ()
{
const rt = this.make.renderTexture({ x: 0, y: 0, width: 800, height: 600 }).setOrigin(0, 0);
const atari = this.add.image(200, 500, 'atlas', 'atari800').setInteractive();
const mushroom = this.add.image(400, 100, 'atlas', 'mushroom2').setInteractive();
const car = this.add.image(650, 500, 'atlas', 'supercars-parsec').setInteractive();
let selected = atari;
atari.on('pointerdown', function ()
{
selected = this;
});
mushroom.on('pointerdown', function ()
{
selected = this;
});
car.on('pointerdown', function ()
{
selected = this;
});
this.input.on('pointermove', pointer =>
{
rt.draw(selected, pointer.x, pointer.y)
.render();
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example,
width: 800,
height: 600
};
const game = new Phaser.Game(config);
Что такое Render Texture и зачем она нужна
Render Texture (текстура отрисовки) — это специальный тип текстуры в Phaser, которая действует как динамический холст. В отличие от статичных изображений, на неё можно «рисовать» другими игровыми объектами (спрайтами, графикой, текстом) в реальном времени с помощью метода draw. Это происходит на уровне GPU, что делает процесс очень эффективным.
Основное преимущество — возможность создавать сложные визуальные композиции, следы, мазки кисти или временные эффекты без создания сотен отдельных игровых объектов. В нашем примере Render Texture становится интерактивным полотном, где мы рисуем выбранным спрайтом.
Подготовка сцены и создание Render Texture
Всё начинается в методе create нашей сцены. Первым делом мы создаём экземпляр Render Texture, который покроет весь экран.
const rt = this.make.renderTexture({ x: 0, y: 0, width: 800, height: 600 }).setOrigin(0, 0);
Здесь this.make.renderTexture создаёт текстуру с началом в точке (0,0), шириной и высотой, равными размеру игры (800x600). Вызов .setOrigin(0, 0) фиксирует точку начала отрисовки в левом верхнем углу текстуры, что упрощает позиционирование.
Далее мы создаём три спрайта из атласа, которые будут выступать в роли наших «кистей». Каждому назначается интерактивность.
const atari = this.add.image(200, 500, 'atlas', 'atari800').setInteractive();
const mushroom = this.add.image(400, 100, 'atlas', 'mushroom2').setInteractive();
const car = this.add.image(650, 500, 'atlas', 'supercars-parsec').setInteractive();
Механика выбора объекта и рисования
Для управления выбором «кисти» мы используем переменную selected и события указателя (pointer). Изначально выбрана atari.
Каждому спрайту назначается обработчик события pointerdown, который переключает текущий выбранный объект.
atari.on('pointerdown', function ()
{
selected = this;
});
Обратите внимание: внутри функции-обработчика this ссылается на сам спрайт (atari, mushroom или car), на котором произошло событие. Это классический для JavaScript контекстный подход.
Ключевая логика рисования заключена в обработчике движения указателя pointermove.
this.input.on('pointermove', pointer =>
{
rt.draw(selected, pointer.x, pointer.y)
.render();
});
При каждом движении мыши метод rt.draw отрисовывает текущий выбранный объект (selected) на Render Texture в координатах указателя (pointer.x, pointer.y). Метод .render() после draw гарантирует немедленное обновление текстуры на экране. Без него изменения могут не отображаться до следующего кадра.
Детали работы метода draw и производительность
Метод draw объекта Render Texture — это сердце нашего примера. Его сигнатура в данном случае: draw(gameObject, x, y). Он берёт визуальное представление игрового объекта (включая его текущий кадр, масштаб, tint) и «штампует» его на текстуру в указанных координатах.
Важно понимать, что draw не создаёт новый инстанс объекта в мире игры. Он лишь копирует его пиксели на текстуру. Это делает операцию очень дешёвой.
Вызов .render() после draw в данном контексте важен, потому что мы обновляем текстуру непрерывно в ответ на движение мыши. В других сценариях (например, отрисовка один раз за кадр) можно вызывать render реже для оптимизации.
// Так мы рисуем выбранный спрайт там, где сейчас курсор
rt.draw(selected, pointer.x, pointer.y);
Поскольку мы используем атлас, selected содержит ссылку на текстуру и конкретное имя кадра (например, 'mushroom2'), которое и будет нарисовано.
Что попробовать дальше
Render Texture в Phaser 3 — это гибкий инструмент для динамической графики. В рассмотренном примере мы реализовали интерактивное рисование выбранным спрайтом. Вы можете экспериментировать: добавьте изменение размера или поворота кисти через параметры draw, реализуйте ластик, очищающий часть текстуры, или создайте систему штампов для построения уровней. Для очистки всей текстуры используйте метод rt.clear(). Попробуйте также рисовать не спрайтами, а графическими примитивами (this.add.graphics) для создания кастомизируемых кистей.
