О чем этот пример

Управление жизненным циклом игры — ключевой навык для создания сложных проектов. В этой статье мы разберем, как корректно уничтожить текущий экземпляр Phaser.Game и создать новый, не перезагружая страницу. Этот подход полезен для реализации перезапуска уровня, смены режима игры или полного сброса состояния приложения. Мы будем использовать пример с кастомным плагином, который демонстрирует чистый способ уничтожения игры и ее последующего восстановления по событию пользователя.

Версия 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.plugin('RandomNamePlugin', 'assets/loader-tests/RandomNamePlugin.js', true);
    }

    create ()
    {
        let plugin = this.plugins.get('RandomNamePlugin');

        let names = plugin.getNames(10);

        names.push('', 'Click to destroy game instance');

        this.add.text(10, 10, names, { font: '16px Courier', fill: '#00ff00' });

        this.input.on('pointerdown', function ()
        {

            this.sys.game.destroy(true);

            document.addEventListener('mousedown', function newGame ()
            {

                game = new Phaser.Game(config);

                document.removeEventListener('mousedown', newGame);

            });

        }, this);
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

let game = new Phaser.Game(config);

Загрузка кастомного плагина

Плагины в Phaser позволяют расширять базовый функционал игры. В данном примере используется плагин RandomNamePlugin, который загружается в методе preload. Ключевой параметр true в методе load.plugin указывает, что плагин должен быть запущен автоматически после загрузки.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.plugin('RandomNamePlugin', 'assets/loader-tests/RandomNamePlugin.js', true);

Использование плагина и отрисовка интерфейса

В методе create мы получаем экземпляр загруженного плагина с помощью this.plugins.get. Плагин предоставляет метод getNames, который генерирует массив случайных имен. После добавления служебных строк этот массив выводится на экран с помощью this.add.text.

let plugin = this.plugins.get('RandomNamePlugin');
let names = plugin.getNames(10);
names.push('', 'Click to destroy game instance');
this.add.text(10, 10, names, { font: '16px Courier', fill: '#00ff00' });

Уничтожение игры и подготовка перезапуска

Основная логика находится в обработчике клика. При срабатывании события pointerdown вызывается метод this.sys.game.destroy(true). Параметр true указывает, что нужно остановить игровой цикл, отключить все системы Phaser и очистить связанные ресурсы.

this.input.on('pointerdown', function () {
    this.sys.game.destroy(true);
}, this);

Создание нового экземпляра игры

После уничтожения игры мы вешаем глобальный обработчик события mousedown на документ. При следующем клике создается новый экземпляр Phaser.Game с исходной конфигурацией, что приводит к полной перезагрузке сцены. Важно удалить обработчик после его срабатывания, чтобы избежать утечек памяти.

document.addEventListener('mousedown', function newGame () {
    game = new Phaser.Game(config);
    document.removeEventListener('mousedown', newGame);
});

Структура конфигурации игры

Конфиг определяет базовые параметры игры: тип рендерера, контейнер в DOM, размеры холста и главную сцену. Переменная game хранится глобально, чтобы к ней можно было обратиться при пересоздании.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};
let game = new Phaser.Game(config);

Что попробовать дальше

Корректное уничтожение и пересоздание игры позволяет эффективно управлять памятью и состоянием приложения. Для экспериментов попробуйте

  1. уничтожать игру не по клику, а по таймеру или игровому событию
  2. передавать в новую игру модифицированный конфиг (например, другие размеры экрана)
  3. сохранять некоторые данные между перезапусками, используя локальное хранилище браузера