О чем этот пример
Render Texture в Phaser 3 — это мощный инструмент для создания динамических текстур прямо во время выполнения игры. В этой статье мы разберем, как не только создавать такие текстуры, но и изменять их размер на лету, что открывает возможности для оптимизации и визуальных эффектов. Вы узнаете, как перерисовать содержимое текстуры после изменения её размеров и использовать результат для множества игровых объектов.
Версия 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('bubble', 'assets/particles/bubble.png');
this.load.image('dude', 'assets/sprites/phaser-dude.png');
}
create ()
{
this.rt = this.make.renderTexture({ width: 100, height: 100 }, false);
this.rt.draw('bubble', 32, 32);
this.rt.draw('dude', 34, 34);
const t = this.rt.saveTexture('bubbleboy');
for (let i = 0; i < 100; 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', () =>
{
this.rt.setSize(50, 50);
this.rt.draw('bubble', 32, 32);
this.rt.draw('dude', 34, 34);
this.rt.render();
}, this);
}
}
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.GameObjects.RenderTexture) — это специальный тип текстуры, которую можно рисовать программно, комбинируя другие изображения, графику или даже целые сцены. Она действует как холст в реальном времени.
Частая задача — подгонять размер такой текстуры под меняющиеся условия игры. Например, вы создали текстуру для спрайта персонажа с эффектом, но потом нужно отобразить его уменьшенную версию для мини-карты. Менять размер каждого спрайта по отдельности неэффективно. Гораздо лучше один раз изменить размер исходной Render Texture, и все спрайты, которые её используют, обновятся автоматически. Это экономит ресурсы и упрощает код.
Создание и первоначальная отрисовка текстуры
В методе create() сцены мы создаем Render Texture и сразу наполняем её графикой.
this.rt = this.make.renderTexture({ width: 100, height: 100 }, false);
Эта строка создает текстуру размером 100x100 пикселей. Второй аргумент false указывает, что текстура не будет добавлена в список отображения сцены как отдельный объект — она существует только как источник данных для спрайтов. После изменения её физического размера с помощью setSize, старая текстура очищается. Чтобы спрайты снова стали видимыми, нужно заново нарисовать на ней нужное содержимое и принудительно обновить, вызвав метод render().
Давайте посмотрим на ключевые шаги в коде.
Создание и первоначальное наполнение текстуры
В методе create() мы инициализируем Render Texture и сразу рисуем на ней два изображения.
this.rt = this.make.renderTexture({ width: 100, height: 100 }, false);
this.rt.draw('bubble', 32, 32);
this.rt.draw('dude', 34, 34);
Сначала создается текстура размером 100x100 пикселей. Второй параметр false указывает, что текстура не должна быть добавлена на экран как отдельный игровой объект. Затем на неё рисуются два загруженных изображения: пузырь (bubble) и персонаж (dude). Координаты (32, 32) и (34, 34) — это точки, относительно которых центрируются изображения при отрисовке на текстуре.
Следующий шаг — сохранение этой нарисованной текстуры в кэш текстур игры под новым ключом.
const t = this.rt.saveTexture('bubbleboy');
Теперь к текстуре можно обращаться по ключу 'bubbleboy', как к обычной загруженной картинке. Мы используем это, чтобы создать 100 спрайтов, разбросанных по сцене.
for (let i = 0; i < 100; i++)
{
const b = this.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(100, 500), 'bubbleboy');
this.bubbles.push(b);
}
Изменение размера и перерисовка
По клику мыши (pointerup) запускается процесс изменения размера Render Texture.
this.input.on('pointerup', () => {
this.rt.setSize(50, 50);
this.rt.draw('bubble', 32, 32);
this.rt.draw('dude', 34, 34);
this.rt.render();
}, this);
1. **`this.rt.setSize(50, 50);`** — этот метод изменяет физические размеры текстуры на 50x50 пикселей. Важно понимать, что после этого вызова текущее содержимое текстуры (наши пузырь и персонаж) **теряется**. Холст становится пустым.
2. **`this.rt.draw(...);`** — поэтому мы обязаны заново нарисовать на текстуре нужные изображения. Координаты (32, 32) остаются прежними, но теперь они отсчитываются от нового, меньшего холста.
3. **`this.rt.render();`** — это ключевой вызов. Он принудительно обновляет текстуру в кэше. Без него спрайты, использующие ключ `'bubbleboy'`, будут отображать пустую или устаревшую текстуру. После `render()` все 100 спрайтов на сцене мгновенно обновятся и станут отображать уменьшенную версию составного изображения.
Важные нюансы и практические советы
* **Очистка содержимого:** Метод `setSize()` не масштабирует старое содержимое, а очищает текстуру. Если вам нужно именно масштабирование, рассмотрите использование `this.rt.setScale()` для игрового объекта Render Texture, добавленного на сцену, или ручное рисование с трансформациями.
* **Производительность:** Операция `render()` может быть затратной, особенно для больших текстур. Изменяйте размер и перерисовывайте текстуры в моменты, когда это не критично для FPS (например, между уровнями или по триггеру, который срабатывает нечасто).
* **Координаты отрисовки:** При перерисовке на текстуре нового размера координаты могут "уехать". Убедитесь, что ключевые элементы попадают в видимую область. Для центрирования можно использовать половину новой ширины и высоты текстуры.
* **Текстура в кэше:** Текстура, сохраненная через `saveTexture()`, является ссылкой. Все дальнейшие манипуляции с исходной Render Texture (`this.rt`) будут автоматически отражаться на всех спрайтах, которые её используют, но только после принудительного вызова `render()`.
Что попробовать дальше
Динамическое управление Render Texture через setSize() и render() — это продвинутая техника для оптимизации памяти (можно хранить одну текстуру разного размера) и создания эффектов (например, постепенное сжатие или размытие цели). Поэкспериментируйте: изменяйте размер в цикле для анимации "пульсации", рисуйте на текстуре разные изображения в зависимости от нового размера или используйте несколько Render Texture для сложных составных спрайтов, чьи части нужно масштабировать независимо.
