О чем этот пример
При разработке игр на Phaser 3 часто возникает необходимость программно останавливать или перезапускать сцены. Однако если на сцене остаются активные игровые объекты, это может привести к ошибкам. Свойство `ignoreDestroy` — это простой способ сообщить движку, что конкретный объект должен пережить уничтожение своей родительской сцены. Эта статья объяснит, как и когда использовать этот флаг на практическом примере, предотвращая типичные сбои при управлении сценами.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
offset;
graphics;
bob;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('atlas', 'assets/atlas/megaset-2.png', 'assets/atlas/megaset-2.json');
}
create ()
{
this.testimage = this.add.image(400, 300, 'atlas', 'hello');
this.testimage.ignoreDestroy = true; // comment out this line and the code works
this.time.delayedCall(1000, ()=> this.scene.stop())
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#2d2d88',
scene: Example
};
const game = new Phaser.Game(config);
Проблема: ошибка при остановке сцены с объектами
В Phaser 3 стандартное поведение при остановке сцены с помощью this.scene.stop() — это уничтожение всех игровых объектов, созданных этой сценой. Иногда такое поведение нежелательно. Например, объект может использоваться в другой сцене или быть частью глобального интерфейса.
В предоставленном исходном коде создается изображение (this.testimage), а через секунду сцена останавливается. Без специальных указаний движок попытается удалить это изображение, что может вызвать конфликт, если объект где-то ещё используется.
this.time.delayedCall(1000, ()=> this.scene.stop())
Решение: флаг ignoreDestroy
Свойство ignoreDestroy — это булевый флаг, доступный для любых игровых объектов (Game Objects). Когда он установлен в true, движок Phaser пропускает этот объект в процессе очистки при остановке или перезапуске сцены. Объект остается в памяти и в текстурах.
В примере этот флаг устанавливается для изображения сразу после его создания. Это прямое указание системе не трогать данный объект.
this.testimage = this.add.image(400, 300, 'atlas', 'hello');
this.testimage.ignoreDestroy = true; // Ключевая строка
Как это работает внутри
Когда вызывается this.scene.stop(), Phaser запускает процесс завершения работы сцены. Частью этого процесса является вызов метода destroy для всех дочерних объектов Display List (списка отображения).
Если у объекта установлено свойство ignoreDestroy, внутренние проверки в методах класса GameObject пропускают его. Объект не удаляется из памяти, не очищаются его текстуры и физические тела (если они есть). Это позволяет безопасно передавать ссылку на этот объект в другую сцену или использовать его как глобальный ресурс.
Важно понимать, что это свойство влияет только на процесс уничтожения, инициированный остановкой или перезапуском сцены. Вручную вызванный object.destroy() всё равно уничтожит объект.
Типичные сценарии использования
1. **Глобальный UI или HUD**: Элементы интерфейса, такие как панель здоровья или счёт, которые должны быть видны на всех сценах игры. 2. **Фоновые объекты**: Статичный фон или декорации, которые переиспользуются между несколькими сценами (например, уровнями). 3. **Общие ресурсы игры**: Сложные объекты, загрузка которых занимает время, и которые нецелесообразно пересоздавать.
// Пример: создание глобальной панели в Boot-сцене
function create() {
this.healthBar = this.add.graphics();
// ... настройка graphics ...
this.healthBar.ignoreDestroy = true; // Сохранить при смене сцен
// Передаем ссылку в реестр игры для доступа из других сцен
this.registry.set('globalHealthBar', this.healthBar);
}
Осторожность и управление памятью
Использование ignoreDestroy требует внимательности, так как может привести к утечкам памяти. Если объект больше не нужен, его необходимо уничтожить вручную.
- **Не устанавливайте этот флаг для временных или одноразовых объектов**.
- **Чётко определяйте жизненный цикл объекта**. Кто и когда его должен уничтожить?
- **Используйте реестр игры (this.registry)** или глобальные переменные для хранения ссылок на такие объекты, чтобы не потерять к ним доступ.
// Пример ручного уничтожения в другой сцене
function onSceneShutdown() {
const globalObj = this.registry.get('myGlobalImage');
if (globalObj) {
globalObj.destroy(); // Явное уничтожение
this.registry.remove('myGlobalImage');
}
}
Что попробовать дальше
Свойство ignoreDestroy — это мощный инструмент для тонкого контроля над жизненным циклом игровых объектов в Phaser 3. Оно позволяет обходить стандартный механизм очистки сцены, что необходимо для создания глобальных или переиспользуемых элементов. Для экспериментов попробуйте создать управляемую игроком фигуру в одной сцене, установить ignoreDestroy, остановить сцену и затем добавить эту же фигуру в другую активную сцену через её реестр. Помните о ручном управлении памятью для таких объектов.
