О чем этот пример
Класс Render Texture в Phaser позволяет создавать текстуры «на лету», комбинируя разные изображения и спрайты. Это мощный инструмент для генерации эффектов, пользовательского интерфейса или динамического контента. Однако при уничтожении Render Texture важно правильно управлять игровыми объектами, которые её используют, иначе можно столкнуться с ошибками рендеринга. Эта статья на практическом примере покажет, как безопасно удалять 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('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', 50, 50);
this.rt.draw('dude', 50, 50);
this.rt.render();
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', () =>
{
// It is YOUR responsibility to remove or change the texture being used by
// any Game Objects that are using the Render Texture *before* you destroy it
this.bubbles.forEach(image =>
{
image.destroy();
});
this.rt.destroy();
});
}
}
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 генерируется программно, что позволяет рисовать на ней другие текстуры, спрайты или графику, а затем использовать результат как единое изображение.
Основные сценарии использования: * Динамическое создание комбинированных спрайтов (например, персонаж с предметом). * Генерация эффектов частиц или фонов. * Создание временных текстур для кастомного UI.
В предоставленном примере мы создадим одну Render Texture, нарисуем на ней два изображения («пузырёк» и «персонажа»), сохраним её как новую текстуру и создадим 100 игровых объектов, использующих эту сгенерированную текстуру.
Создание и наполнение Render Texture
В методе create() сцены создаётся и наполняется Render Texture. Ключевые этапы:
1. Создание Render Texture с заданными размерами (100x100 пикселей).
2. Последовательное рисование на ней двух загруженных изображений с помощью метода draw().
3. Финализация текстуры вызовом render().
4. Сохранение результата в текстуру кэша под именем 'bubbleboy' с помощью saveTexture().
this.rt = this.make.renderTexture({ width: 100, height: 100 }, false);
this.rt.draw('bubble', 50, 50);
this.rt.draw('dude', 50, 50);
this.rt.render();
const t = this.rt.saveTexture('bubbleboy');
После выполнения этого кода в менеджере текстур появляется новая текстура 'bubbleboy', которую можно использовать так же, как любую загруженную.
Использование сгенерированной текстуры
Как только текстура сохранена в кэше, её можно применять для создания игровых объектов. В примере создаётся 100 объектов Image, которые используют текстуру '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);
}
Все созданные изображения добавляются в массив bubbles для последующего управления. Важно понимать, что теперь эти объекты жестко ссылаются на данные текстуры 'bubbleboy', которая, в свою очередь, зависит от исходной Render Texture this.rt.
Безопасное уничтожение Render Texture
Это ключевой момент. Нельзя просто взять и удалить (destroy) Render Texture, пока её данные используются какими-либо игровыми объектами. Если это сделать, объекты попытаются отрисовать несуществующую текстуру, что приведёт к ошибке.
Порядок безопасного удаления, показанный в обработчике клика: 1. Уничтожить (или изменить текстуру у) все игровые объекты, которые используют сгенерированную текстуру. 2. Только после этого уничтожить саму Render Texture.
this.input.on('pointerup', () =>
{
// Уничтожаем все объекты, использующие текстуру, ПЕРЕД удалением Render Texture
this.bubbles.forEach(image =>
{
image.destroy();
});
this.rt.destroy();
});
Комментарий в коде прямо указывает: это ВАША ответственность — удалить или изменить текстуру у всех игровых объектов, использующих Render Texture, *до* её уничтожения.
Что попробовать дальше
Работа с Render Texture открывает возможности для динамического создания контента, но требует внимательного управления жизненным циклом. Главное правило: сначала освободите все зависимые объекты, затем удаляйте саму текстуру. Для экспериментов попробуйте: изменить порядок удаления (сначала rt.destroy()), чтобы увидеть ошибку; не уничтожать объекты, а сменить им текстуру на другую перед удалением rt; или создать несколько Render Texture и переключать их у объектов в реальном времени.
