Плагины
Создание и использование плагинов Phaser 4 — три формы плагинов (глобальный, сценический, игрового объекта) и разобранный пример системы сохранения.
Плагин — это самодостаточный модуль, встраивающийся в жизненный цикл Phaser. Phaser 4 поддерживает три формы, каждая со своей областью видимости и жизненным циклом:
| Вид | Существует в | Жизненный цикл | Использовать для |
|---|---|---|---|
| Глобальный | game.plugins | Создаётся вместе с игрой; сохраняется. | Межсценовые службы (сохранение, аналитика, сеть). |
| Сценический | scene.plugins | Создаётся для каждой сцены; привязан к её жизненному циклу. | Помощники уровня сцены (менеджер эффектов, движок диалогов). |
| Игрового объекта | Расширяет this.add / this.make | Прикрепляет фабрику к сценам, которые её подключают. | Пользовательские типы игровых объектов (HealthBar, Minimap). |
Выбирайте наименьшую подходящую область видимости. Глобальный плагин, который использует лишь одна сцена, — это просто утечка.
Глобальный плагин
Класс, расширяющий Phaser.Plugins.BasePlugin. Он создаётся один раз при запуске игры и доступен отовсюду через this.plugins.get('Name').
class SavePlugin extends Phaser.Plugins.BasePlugin {
private readonly KEY = 'save-v1';
save(state: object) {
localStorage.setItem(this.KEY, JSON.stringify(state));
}
load<T = unknown>(): T | null {
const raw = localStorage.getItem(this.KEY);
return raw ? (JSON.parse(raw) as T) : null;
}
clear() {
localStorage.removeItem(this.KEY);
}
}
Зарегистрируйте его в конфигурации игры:
new Phaser.Game({
plugins: {
global: [{ key: 'Save', plugin: SavePlugin, start: true, mapping: 'save' }],
},
});
start: true создаёт экземпляр немедленно; mapping: 'save' делает его доступным как this.save в каждой сцене. Без mapping к нему обращаются через this.plugins.get('Save').
Использование:
this.save.save({ level: 3, hp: 80 });
const restored = this.save.load<{ level: number; hp: number }>();
Сценический плагин
Класс, расширяющий Phaser.Plugins.ScenePlugin. Каждая сцена получает собственный экземпляр, и плагин может встраиваться в события жизненного цикла сцены:
class DialogPlugin extends Phaser.Plugins.ScenePlugin {
private activeBox?: Phaser.GameObjects.Container;
boot() {
this.systems.events.on('shutdown', this.shutdown, this);
this.systems.events.on('destroy', this.destroy, this);
}
say(text: string) {
this.activeBox?.destroy();
const scene = this.scene!;
this.activeBox = scene.add.container(scene.scale.width / 2, scene.scale.height - 80);
this.activeBox.add(scene.add.rectangle(0, 0, 600, 100, 0x000000, 0.7));
this.activeBox.add(scene.add.text(0, 0, text, { fontSize: '20px' }).setOrigin(0.5));
}
private shutdown() {
this.activeBox?.destroy();
this.activeBox = undefined;
}
}
Регистрация для каждой сцены:
plugins: {
scene: [{ key: 'Dialog', plugin: DialogPlugin, mapping: 'dialog' }],
}
Теперь this.dialog.say('Hello.') работает в любой сцене, которая получила эту регистрацию.
Плагин игрового объекта
Третья форма добавляет новые фабрики в this.add и this.make. Каноничный паттерн Phaser 4 — обычная функция, зарегистрированная через Phaser.GameObjects.GameObjectFactory.register:
class HealthBar extends Phaser.GameObjects.Container {
private readonly fg: Phaser.GameObjects.Rectangle;
constructor(scene: Phaser.Scene, x: number, y: number, max: number) {
super(scene, x, y);
const bg = scene.add.rectangle(0, 0, 120, 10, 0x222222);
this.fg = scene.add.rectangle(-60, 0, 120, 10, 0x44dd44).setOrigin(0, 0.5);
this.add([bg, this.fg]);
this.setData('max', max);
this.setData('value', max);
}
set(value: number) {
this.setData('value', value);
this.fg.width = 120 * (value / (this.getData('max') as number));
}
}
Phaser.GameObjects.GameObjectFactory.register('healthBar', function (x, y, max) {
const hb = new HealthBar(this.scene, x, y, max);
this.displayList.add(hb);
this.updateList.add(hb);
return hb;
});
Теперь this.add.healthBar(20, 20, 100) работает в любой сцене.
Для пользователей TypeScript дополните тип фабрики:
declare global {
namespace Phaser.GameObjects {
interface GameObjectFactory {
healthBar(x: number, y: number, max: number): HealthBar;
}
}
}
Подводные камни жизненного цикла
- Не обращайтесь к
this.sceneдоboot. Сценические плагины создаются рано;this.sceneустанавливается вboot. - Очищайте подписки в
shutdown. Сцены могут запускаться и останавливаться многократно; плагины, привязывающиеся к событиям сцены без отписки, будут давать утечки. - Синглтоны глобальных плагинов. Глобальный плагин — это синглтон: храните состояние, специфичное для сцены, внутри сцен, а не в плагине.
Упаковка
Для совместного использования между проектами поставляйте как ESM-модуль, где класс плагина является экспортом по умолчанию, плюс вызов регистрации (или помощник register(game), если хотите, чтобы потребители делали это явно). Не держите никаких зависимостей от Phaser в рантайм-импортах пакета — Phaser принадлежит потребителю; объявите его как peerDependency.
Связанные материалы
- Сцены — где живут сценические плагины.
- Игровые объекты — что расширяют плагины игровых объектов.