О чем этот пример
Phaser предлагает мощную систему плагинов, которая позволяет расширять функциональность движка. Чаще всего плагины регистрируются глобально при конфигурации игры, но иногда возникает необходимость добавить новый инструмент прямо во время выполнения, например, для специфичной механики конкретной сцены. В этой статье мы разберем, как динамически устанавливать плагины в менеджер плагинов Phaser, используя метод `install()`, и покажем практический пример создания генератора случайных имен.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class RandomNamePlugin extends Phaser.Plugins.BasePlugin {
constructor (pluginManager)
{
super(pluginManager);
this.syllables1 = [ 'fro', 'tir', 'nag', 'bli', 'mon', 'zip' ];
this.syllables2 = [ 'fay', 'shi', 'zag', 'blarg', 'rash', 'izen' ];
this.current = this.syllables1;
}
changeSet ()
{
this.current = this.syllables2;
}
getName ()
{
let name = '';
for (let i = 0; i < Phaser.Math.Between(2, 4); i++)
{
name = name.concat(Phaser.Utils.Array.GetRandom(this.current));
}
return Phaser.Utils.String.UppercaseFirst(name);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: {
preload: preload,
create: create
}
};
let game = new Phaser.Game(config);
function preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('elephant', 'assets/sprites/elephant.png');
}
function create ()
{
// Install two instances of the 'RandomNamePlugin' running in the Plugin Manager.
// We will reference them with the keys 'myPluginRef1' and 'myPluginRef2'
// `install` will return the plugins because we are calling this in `create` and the Game
// has booted by now. `install` returns undefined if the game is not yet booted.
let plugin1 = this.plugins.install('myPluginRef1', RandomNamePlugin, true);
let plugin2 = this.plugins.install('myPluginRef2', RandomNamePlugin, true);
// Make the 2nd instance of our plugin use the alternative set of syllables
plugin2.changeSet();
let name1 = plugin1.getName();
let name2 = plugin2.getName();
this.add.image(300, 300, 'elephant');
this.add.image(500, 300, 'elephant');
this.add.text(250, 400, name1, { font: '16px Courier', fill: '#00ff00' });
this.add.text(450, 400, name2, { font: '16px Courier', fill: '#ffff00' });
}
Создаем собственный плагин
Любой пользовательский плагин в Phaser должен наследоваться от базового класса Phaser.Plugins.BasePlugin. Это дает доступ к системе плагинов и жизненному циклу игры.
В конструкторе мы инициализируем данные, которые будут использоваться плагином. В нашем примере это два набора слогов для генерации имен и указатель на текущий активный набор.
class RandomNamePlugin extends Phaser.Plugins.BasePlugin {
constructor (pluginManager) {
super(pluginManager);
this.syllables1 = [ 'fro', 'tir', 'nag', 'bli', 'mon', 'zip' ];
this.syllables2 = [ 'fay', 'shi', 'zag', 'blarg', 'rash', 'izen' ];
this.current = this.syllables1;
}
}
Метод changeSet() — это пример публичного метода плагина, который меняет его внутреннее состояние (переключает набор слогов).
changeSet () {
this.current = this.syllables2;
}
Метод getName() — основная функциональность плагина. Он использует встроенные утилиты Phaser для генерации случайного имени:
- Phaser.Math.Between(2, 4) определяет количество слогов в имени.
- Phaser.Utils.Array.GetRandom(this.current) выбирает случайный слог из текущего набора.
- Phaser.Utils.String.UppercaseFirst(name) делает первую букву имени заглавной.
getName () {
let name = '';
for (let i = 0; i < Phaser.Math.Between(2, 4); i++) {
name = name.concat(Phaser.Utils.Array.GetRandom(this.current));
}
return Phaser.Utils.String.UppercaseFirst(name);
}
Динамическая установка плагинов в сцене
Обычно плагины добавляются в глобальную конфигурацию игры через поле plugins. Однако Phaser позволяет установить плагин уже после загрузки игры, прямо внутри сцены, с помощью метода this.plugins.install().
Ключевые моменты вызова install():
1. **Первый аргумент (key)** — уникальная строковая ссылка, по которой можно будет получить этот экземпляр плагина из менеджера.
2. **Второй аргумент (plugin)** — класс (конструктор) плагина, который нужно инстанцировать.
3. **Третий аргумент (start)** — булево значение, указывающее, нужно ли сразу запускать плагин (вызывать его метод start).
4. **Возвращаемое значение** — если игра уже загружена (booted), метод возвращает экземпляр созданного плагина. В противном случае возвращается undefined.
В функции create мы устанавливаем два независимых экземпляра одного и того же плагина под разными ключами.
function create ()
{
let plugin1 = this.plugins.install('myPluginRef1', RandomNamePlugin, true);
let plugin2 = this.plugins.install('myPluginRef2', RandomNamePlugin, true);
}
Теперь у нас есть два плагина: plugin1 и plugin2. Мы можем управлять ими независимо. Например, для второго экземпляра меняем набор слогов.
plugin2.changeSet();
Затем получаем сгенерированные имена от каждого плагина и выводим их на экран.
let name1 = plugin1.getName();
let name2 = plugin2.getName();
this.add.text(250, 400, name1, { font: '16px Courier', fill: '#00ff00' });
this.add.text(450, 400, name2, { font: '16px Courier', fill: '#ffff00' });
Когда это полезно на практике?
Динамическая установка плагинов открывает несколько сценариев для архитектуры игры:
* **Модульные механики уровня:** Если в игре есть особый уровень с уникальной физикой, логикой врагов или системой диалогов, вы можете создать плагин для этой механики и установить его только при загрузке этой конкретной сцены. По завершении уровня плагин можно удалить (this.plugins.remove()), чтобы освободить ресурсы.
* **Гибкие инструменты разработки:** Вы можете создать плагин-инспектор для отладки, который будет показывать состояние объектов только в нужных сценах, и включать его по горячей клавише.
* **Изоляция кода:** Сложную логику, не относящуюся напрямую к сцене (например, алгоритм генерации лабиринта или менеджер достижений), можно вынести в плагин. Это делает код сцены чище, а логику — переиспользуемой.
Важно помнить, что такие «локальные» плагины доступны только в том экземпляре менеджера плагинов (this.plugins), в котором были установлены, обычно это плагины сцены (ScenePlugin).
Что попробовать дальше
Метод install() в Phaser — это мощный инструмент для гибкого расширения функциональности игры прямо во время выполнения. Он позволяет создавать модульные, изолированные куски логики и подключать их по мере необходимости, что улучшает архитектуру проекта и управление ресурсами.
**Идеи для экспериментов:**
1. Создайте плагин для управления частицами, который устанавливается только на уровнях с «магической» атмосферой.
2. Реализуйте плагин-помощник для тестирования, который по команде спавнит врагов вокруг игрока, и устанавливайте его только в debug-режиме.
3. Попробуйте создать плагин, который динамически меняет параметры физического мира (например, гравитацию) и переключайте его экземпляры для создания разных игровых зон.
