Передача данных между сценами через init

Phaser — мощная библиотека для разработки 2D-игр на JavaScript, где архитектура сцен играет ключевую роль. Каждая сцена представляет собой отдельный жизненный цикл с методами preload, create, update и другими. Важной задачей при построении сложных игр становится обмен данными между сценами, особенно при переходе от одной сцены к другой. Одним из наиболее элегантных решений является использование метода init.


Метод init в сцене

Метод init вызывается перед preload и create при запуске сцены. Его основное назначение — принять и подготовить данные, которые будут использоваться в этой сцене. В отличие от глобальных переменных или менеджеров состояния, init позволяет передавать данные локально и безопасно, минимизируя побочные эффекты.

Сигнатура метода проста:

init(data) {
    this.dataFromPreviousScene = data;
}
  • data — объект с любыми значениями, которые необходимо передать.
  • Внутри метода init обычно создаются свойства сцены для хранения этих данных.

Передача данных при запуске сцены

Для передачи данных используется метод scene.start, который может принимать объект с данными в качестве второго аргумента:

this.scene.start('GameScene', { score: 150, playerName: 'Alex' });

В целевой сцене эти данные принимаются в методе init:

class GameScene extends Phaser.Scene {
    constructor() {
        super({ key: 'GameScene' });
    }

    init(data) {
        this.score = data.score || 0;
        this.playerName = data.playerName || 'Player';
    }

    create() {
        this.add.text(100, 100, `Игрок: ${this.playerName}`, { fontSize: '24px', fill: '#fff' });
        this.add.text(100, 150, `Счёт: ${this.score}`, { fontSize: '24px', fill: '#fff' });
    }
}

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


Передача сложных объектов

init позволяет передавать не только примитивные значения, но и сложные структуры, включая массивы, объекты и даже экземпляры классов:

const playerData = {
    name: 'Alex',
    inventory: ['sword', 'shield'],
    stats: { hp: 100, mana: 50 }
};

this.scene.start('GameScene', { player: playerData });

В сцене:

init(data) {
    this.player = data.player;
    this.player.inventory.push('potion'); // можно модифицировать копию объекта
}

При работе с большими объектами важно помнить, что Phaser не клонирует объект автоматически. Если требуется независимая копия, необходимо использовать глубокое копирование (JSON.parse(JSON.stringify(obj)) или специализированные функции).


Разница между init и data менеджером сцены

Phaser также предоставляет Scene Data Manager (this.data) для хранения состояния, доступного между сценами. Однако метод init имеет ряд преимуществ:

  • Данные передаются только при запуске сцены, без необходимости глобальных ссылок.
  • Позволяет обновлять состояние сцены при каждом старте.
  • Упрощает тестирование и декомпозицию кода, так как сцена не зависит от глобальных объектов.

Пример:

// Менеджер данных
this.data.set('score', 200);
this.scene.start('GameScene'); // data сохраняется между сценами

// Использование init
this.scene.start('GameScene', { score: 200 }); // данные передаются локально

Использование init делает код более предсказуемым и безопасным.


Практическая организация передачи данных

  1. Создание объекта с данными:
const levelData = {
    levelNumber: 3,
    enemies: ['goblin', 'orc'],
    bonusPoints: 50
};
  1. Передача данных при смене сцены:
this.scene.start('LevelScene', levelData);
  1. Инициализация сцены через init:
init(data) {
    this.levelNumber = data.levelNumber;
    this.enemies = data.enemies;
    this.bonusPoints = data.bonusPoints;
}
  1. Использование данных в create:
create() {
    this.add.text(50, 50, `Уровень ${this.levelNumber}`, { fontSize: '28px', fill: '#fff' });
    this.enemies.forEach((enemy, index) => {
        this.add.text(50, 100 + index * 30, `Враг: ${enemy}`, { fontSize: '20px', fill: '#f00' });
    });
}

Советы по использованию init

  • Всегда проверять наличие данных: data.score || 0.
  • Не хранить в init объекты, которые требуют асинхронной загрузки. Для этого лучше использовать preload или create.
  • Для передачи больших структур можно комбинировать init и Scene Data Manager, сохраняя ключевые ссылки через init.
  • Использовать init для передачи временных параметров сцены, а глобальный data менеджер — для постоянного состояния игры.

Примеры типичных сценариев

  1. Передача счёта и имени игрока между сценами меню и игрой.
  2. Передача настроек уровня от сцены выбора уровня к сцене игры.
  3. Передача результатов боя или статистики после мини-игры в основную сцену.

Метод init обеспечивает гибкую и структурированную передачу данных, позволяя строить сцены как независимые, переиспользуемые модули с предсказуемым поведением.