О чем этот пример
Разработка игры с десятками сцен превращает один файл в нечитаемую простыню кода. Phaser позволяет выносить логику сцен в отдельные файлы и загружать их по мере необходимости. Это основа модульной архитектуры, которая упрощает поддержку, командную работу и динамическую подгрузку контента. В этой статье разберем, как правильно загружать внешние сцены и избежать типичных ошибок.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene {
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
// It's essential that the key given here is the exact class name used in the JS file. It's case-sensitive.
// See the SceneB.js file and documentation for details.
this.load.sceneFile('ExternalScene', 'assets/loader-tests/ExternalScene.js');
}
create ()
{
this.scene.start('myScene');
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#000',
scene: Example
};
const game = new Phaser.Game(config);
Зачем нужна загрузка сцен из файлов
Когда игра растет, хранение всех сцен в одном основном файле становится проблемой. Это замедляет первоначальную загрузку и усложняет навигацию по коду. Метод this.load.sceneFile() решает эту проблему, позволяя разбить игру на логические модули.
Вы можете разрабатывать меню, уровни и экраны результатов в отдельных файлах. Такой подход особенно полезен для: * Больших проектов с командой разработчиков. * Игр с динамически загружаемыми уровнями (DLC, пользовательский контент). * Структурирования кода по принципу одной ответственности.
Ключевой API: `load.sceneFile()`
Метод this.load.sceneFile() загружает JavaScript-файл, содержащий класс сцены, и регистрирует его в менеджере сцен Phaser. Его сигнатура проста, но есть важные нюансы.
this.load.sceneFile(key, url);
* key (строка): Уникальный ключ для идентификации сцены. **Это должен быть точный, чувствительный к регистру идентификатор сцены**, который используется в this.scene.start(), this.scene.launch() или в конфигурации игры.
* url (строка): Путь к JS-файлу с классом сцены.
Важно: этот метод только загружает и регистрирует класс. Самостоятельный запуск сцены не происходит.
Разбор примера кода: шаг за шагом
Рассмотрим пример, где основная сцена служит загрузчиком для внешней сцены.
**1. Настройка базового URL:** Перед загрузкой файла полезно установить базовый путь. Это сокращает дублирование в URL.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
**2. Загрузка файла сцены:** Здесь происходит магия. Мы говорим загрузчику: "Возьми файл по этому адресу и зарегистрируй его содержимое как сцену с ключом 'ExternalScene'."
this.load.sceneFile('ExternalScene', 'assets/loader-tests/ExternalScene.js');
Ключ 'ExternalScene' должен совпадать с тем, который используется в загружаемом файле ExternalScene.js (например, в его super('ExternalScene') или в системном ключе).
**3. Запуск загруженной сцены:**
После завершения загрузки в методе create() мы запускаем уже зарегистрированную сцену по её ключу.
this.scene.start('myScene');
**Внимание:** В данном примере есть несоответствие. Код загружает сцену с ключом 'ExternalScene', а запускает 'myScene'. Для работоспособности ключи должны совпадать, либо в ExternalScene.js должна быть сцена с ключом 'myScene'. Это частая ошибка новичков.
Структура внешнего файла сцены
Чтобы загрузка сработала, загружаемый файл должен корректно экспортировать класс, унаследованный от Phaser.Scene. Phaser автоматически выполнит этот файл и зарегистрирует класс.
Пример содержимого ExternalScene.js:
class ExternalScene extends Phaser.Scene {
constructor() {
// Ключ, под которым сцена будет доступна в системе, передается в super()
super({ key: 'ExternalScene' });
}
create() {
this.add.text(100, 100, 'Это внешняя сцена!', { fill: '#0f0' });
}
}
Критически важно, чтобы ключ, переданный в конструктор сцены ('ExternalScene'), совпадал с ключом, использованным в load.sceneFile(). Именно по этому ключу вы будете обращаться к сцене из других частей игры.
Лучшие практики и частые ошибки
**1. Регистр символов имеет значение:**
'externalscene', 'ExternalScene' и 'EXTERNALSCENE' — это три разных ключа для Phaser. Будьте последовательны.
**2. Загрузка в preload:**
Метод load.sceneFile() работает через систему загрузки Phaser, поэтому его вызов возможен только в preload() или до начала загрузки.
**3. Не смешивайте с конфигурацией:**
Внешние сцены, загруженные через sceneFile, **не нужно** добавлять в массив scene в конфиге игры. Они регистрируются динамически.
**4. Проверка пути (URL):**
Самая частая проблема — 404 ошибка. Убедитесь, что путь к файлу корректен. Использование setBaseURL() помогает избежать ошибок в длинных путях.
// Плохо: легко ошибиться в длинном пути
this.load.sceneFile('Level1', 'https://mycdn.com/game/assets/scenes/world2/level1.js');
// Лучше
this.load.setBaseURL('https://mycdn.com/game/');
this.load.sceneFile('Level1', 'assets/scenes/world2/level1.js');
Что попробовать дальше
Использование load.sceneFile() — это мощный шаг к созданию масштабируемой и поддерживаемой игры на Phaser. Он отделяет логику сцен от их загрузки, открывая путь к сложным архитектурным решениям.
**Идеи для экспериментов:**
1. Реализуйте систему загрузки уровней "на лету": когда игрок выбирает уровень в меню, загрузите файл с его сценой и сразу запустите.
2. Создайте плагин или систему, которая по конфигурационному JSON-файлу загружает список необходимых сцен для текущей игровой сессии.
3. Поэкспериментируйте с отложенной загрузкой: загружайте сцены для следующего уровня в фоновом режиме, пока игрок смотрит кат-сцену.
