Создание сцены через класс и через объект-конфиг

Phaser — это мощная библиотека для разработки 2D-игр на JavaScript, предоставляющая гибкие средства для управления сценами. Сцена в Phaser представляет собой отдельный модуль игры, содержащий логику отображения, обработки ввода и анимаций. Существует два основных способа создания сцены: через класс и через объект-конфиг. Каждый из подходов имеет свои преимущества и особенности.


Создание сцены через класс

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

class MainScene extends Phaser.Scene {
    constructor() {
        super({ key: 'MainScene' }); // уникальный ключ сцены
    }

    preload() {
        // Загрузка ресурсов: спрайтов, аудио, тайлов
        this.load.image('player', 'assets/player.png');
        this.load.audio('bgm', 'assets/music.mp3');
    }

    create() {
        // Инициализация объектов на сцене
        this.player = this.add.sprite(400, 300, 'player');
        this.sound.play('bgm', { loop: true });
        
        // Настройка ввода
        this.cursors = this.input.keyboard.createCursorKeys();
    }

    update(time, delta) {
        // Логика обновления сцены каждый кадр
        if (this.cursors.left.isDown) {
            this.player.x -= 5;
        } else if (this.cursors.right.isDown) {
            this.player.x += 5;
        }

        if (this.cursors.up.isDown) {
            this.player.y -= 5;
        } else if (this.cursors.down.isDown) {
            this.player.y += 5;
        }
    }
}

Ключевые моменты при использовании класса:

  • constructor() принимает объект с ключом сцены. Ключ обязателен для управления несколькими сценами.
  • Методы preload(), create(), update() — стандартные точки жизненного цикла сцены.
  • Класс позволяет хранить состояние сцены через свойства объекта (this.player, this.cursors).
  • Поддержка наследования упрощает создание специализированных сцен, например, для меню, уровней или босс-файтов.

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


Создание сцены через объект-конфиг

Объект-конфиг предоставляет более декларативный способ создания сцены. Вместо создания класса можно передать объект с методами жизненного цикла непосредственно в конфигурацию Phaser.

const MainSceneConfig = {
    key: 'MainScene',
    preload: function () {
        this.load.image('player', 'assets/player.png');
        this.load.audio('bgm', 'assets/music.mp3');
    },
    create: function () {
        this.player = this.add.sprite(400, 300, 'player');
        this.sound.play('bgm', { loop: true });
        this.cursors = this.input.keyboard.createCursorKeys();
    },
    update: function () {
        if (this.cursors.left.isDown) {
            this.player.x -= 5;
        } else if (this.cursors.right.isDown) {
            this.player.x += 5;
        }

        if (this.cursors.up.isDown) {
            this.player.y -= 5;
        } else if (this.cursors.down.isDown) {
            this.player.y += 5;
        }
    }
};

Особенности использования объекта-конфига:

  • Позволяет быстро создавать простые сцены без объявления класса.
  • Методы жизненного цикла (preload, create, update) задаются как функции объекта.
  • Подходит для небольших игр и прототипов, где сцена не требует сложной структуры.
  • Легко интегрируется напрямую в конфигурацию Phaser.Game, например:
const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: MainSceneConfig,
    physics: { default: 'arcade' }
};

const game = new Phaser.Game(config);

Сравнение подходов

Параметр Класс Объект-конфиг
Структура Чётко организованная, методы класса Более плоская, декларативная
Наследование Поддерживается Нет
Масштабируемость Отличная для больших проектов Подходит для простых или прототипных сцен
Поддержка this Всегда указывает на экземпляр сцены Всегда указывает на сцену, но не поддерживает super

Использование классов предпочтительно для крупных проектов с множеством сцен, сложной логикой и взаимодействием между ними. Объект-конфиг удобен для быстрых прототипов, небольших уровней и одноразовых сцен.


Инициализация игры с несколькими сценами

При работе с несколькими сценами можно комбинировать оба подхода. Например, меню создаётся через объект-конфиг, а основной игровой уровень через класс:

const MenuScene = {
    key: 'MenuScene',
    create: function () {
        this.add.text(400, 300, 'Start Game', { fontSize: '32px', fill: '#fff' })
            .setOrigin(0.5)
            .setInteractive()
            .on('pointerdown', () => this.scene.start('MainScene'));
    }
};

const gameConfig = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: [MenuScene, MainScene],
    physics: { default: 'arcade' }
};

const game = new Phaser.Game(gameConfig);

Такой подход обеспечивает гибкость: простые интерфейсные сцены можно создавать декларативно, а сложные игровые уровни — через классы с полной поддержкой ООП.


Управление жизненным циклом сцены

Фреймворк предоставляет встроенные методы управления сценами:

  • this.scene.start(key) — переход на другую сцену.
  • this.scene.pause(key) / this.scene.resume(key) — временная приостановка и возобновление сцены.
  • this.scene.stop(key) — остановка сцены и освобождение ресурсов.
  • this.scene.launch(key) — запуск сцены поверх текущей.

Эти методы работают одинаково для классов и объектов-конфига, что делает их взаимозаменяемыми при создании архитектуры игры.


Работа с состоянием сцены

Хранение состояния и данных сцены реализуется через свойства this:

this.score = 0;
this.playerHealth = 100;

В классах можно дополнительно использовать наследование и методы для инкапсуляции логики:

class EnemyScene extends Phaser.Scene {
    constructor() {
        super({ key: 'EnemyScene' });
        this.enemies = [];
    }

    addEnemy(x, y) {
        const enemy = this.add.sprite(x, y, 'enemy');
        this.enemies.push(enemy);
    }

    removeEnemy(enemy) {
        this.enemies = this.enemies.filter(e => e !== enemy);
        enemy.destroy();
    }
}

Для объектов-конфига состояние хранится аналогично через this, но наследование и методы ограничены функциональными возможностями объекта.


Итоговая структура

Использование классов и объектов-конфига в Phaser позволяет комбинировать гибкость и простоту. Классы подходят для масштабируемой, объектно-ориентированной архитектуры, а объект-конфиг ускоряет разработку прототипов и интерфейсов. Управление сценами и их жизненный цикл остаются одинаковыми для обоих подходов, обеспечивая единообразный API и легкость интеграции.