О чем этот пример
При работе с несколькими сценами в Phaser имена методов вроде `this.add` или `this.load` могут казаться слишком общими и привести к путанице. Механизм Scene Injection Map позволяет переопределить эти имена на этапе создания сцены, сделав код более выразительным и явным. Это особенно полезно в больших проектах, где сцены разрабатываются разными программистами, или когда вы хотите подчеркнуть специфичную роль метода в конкретном контексте. В этой статье мы разберем, как работает конфигурация `map` в конструкторе сцены, и покажем практический пример, где `this.add` превращается в `this.makeStuff`, а `this.load` — в `this.loader`.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor() {
super({
key: 'Example',
map: {
add: 'makeStuff',
load: 'loader'
}
});
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.loader.image('face', 'assets/pics/bw-face.png');
}
create ()
{
this.makeStuff.image(400, 300, 'face');
console.log(this);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что такое Scene Injection Map?
В Phaser 3 ключевые системы, такие как загрузка ассетов (LoadPlugin) или фабрика игровых объектов (GameObjectFactory), автоматически внедряются в каждую сцену как свойства. По умолчанию они доступны через this.load и this.add.
Однако конструктор сцены (super()) принимает объект конфигурации. Одно из его полей — map — позволяет переопределить имена, под которыми эти плагины будут доступны в контексте текущей сцены. Это не создает новые методы, а лишь дает существующим альтернативные (или дополнительные) названия.
constructor() {
super({
key: 'Example',
map: {
add: 'makeStuff', // Теперь фабрика объектов доступна как this.makeStuff
load: 'loader' // А плагин загрузки — как this.loader
}
});
}
После такой настройки оригинальные имена (this.add, this.load) перестают работать в этой сцене. Использовать можно только новые.
Анализ примера: переименование в действии
Рассмотрим код из примера. В методе preload для загрузки изображения используется не стандартный this.load.image, а переименованный this.loader.image.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.loader.image('face', 'assets/pics/bw-face.png');
}
Обратите внимание: метод setBaseURL все еще вызывается у this.load. Это возможно потому, что map заменяет только корневое свойство. Внутренние методы самого плагина (load.image, load.setBaseURL) остаются неизменными. Важно, что после объявления map: { load: 'loader' } обращение к this.load.image вызовет ошибку, так как свойства load у сцены больше нет.
В методе create для создания спрайта используется новый псевдоним this.makeStuff.image.
create ()
{
this.makeStuff.image(400, 300, 'face');
console.log(this);
}
Вызов console.log(this) поможет в консоли браузера убедиться, что у сцены теперь есть свойства makeStuff и loader, но отсутствуют add и load.
Почему это может быть полезно?
1. **Ясность кода.** В сложной сцене, посвященной, например, построению UI, имя `this.makeUI` или `this.build` читается лучше, чем общее `this.add`.
2. **Избежание конфликтов.** Если вы используете миксины или собственные методы с похожими именами, их можно развести.
3. **Стилизация архитектуры.** Названия можно подбирать под доменную логику конкретной сцены (например, `this.spawn` для сцены с врагами).
Важное ограничение: переименовывать можно только ключевые свойства, внедряемые Phaser. Их список приведен в документации. Например, physics, input, cameras тоже можно перемапить.
// Теоретический пример расширенного map
map: {
add: 'factory',
load: 'assets',
physics: 'simulation'
}
Порядок использования и типичные ошибки
1. **Объявление в конструкторе:** Конфигурация map задается единожды при вызове super() в конструкторе сцены. Изменить ее позже нельзя.
2. **Потеря стандартных имен:** После переопределения оригинальное имя становится недоступным. Если ваш плагин или код сторонней библиотеки рассчитывает на this.add, это сломает его работу.
3. **Проверка в консоли:** Всегда используйте console.log(this), чтобы проверить, какие свойства появились у сцены после инъекции.
create ()
{
// Если map задан как в примере, этот код выбросит ошибку:
// this.add.image(400, 300, 'face'); // ОШИБКА! this.add is undefined
// А этот — отработает:
this.makeStuff.image(400, 300, 'face');
}
4. **Не влияет на другие сцены:** Переименование действует только в рамках одного класса сцены. Другие сцены в проекте продолжат использовать стандартные имена, если для них не задан свой map.
Что попробовать дальше
Scene Injection Map — это мощный инструмент кастомизации API Phaser под нужды конкретной сцены. Он помогает писать более выразительный и предметно-ориентированный код. Хотя в небольших проектах его польза может быть неочевидна, в больших кодобазах или при интеграции сторонних модулей он становится ценным средством для предотвращения путаницы.
**Идеи для экспериментов:** Попробуйте создать сцену, где this.add станет this.spawn, а this.physics.add — this.world.add. Или реализуйте сцену-билдер интерфейса, где фабрика объектов будет называться this.ui. Посмотрите, как изменится восприятие кода и станет ли логика сцены понятнее с первого взгляда.
