О чем этот пример

Плагины в Phaser позволяют инкапсулировать и переиспользовать игровую логику, например, управление движением объектов. Однако часто возникает необходимость включать и выключать эту логику динамически во время выполнения игры — например, по клику мыши или при смене состояния уровня. В этой статье мы разберем, как правильно создавать плагин с методами `start` и `stop`, и как управлять его активностью из основного кода сцены. Это полезно для оптимизации (отключение неиспользуемых систем) и гибкого контроля над игровыми процессами.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class MoveSpritePlugin extends Phaser.Plugins.BasePlugin {

    constructor (pluginManager)
    {
        super(pluginManager);

        this.sprite;
    }

    init ()
    {
        console.log('init');
    }

    start ()
    {
        console.log('start');

        var eventEmitter = this.game.events;

        eventEmitter.on('step', this.update, this);
    }

    stop ()
    {
        console.log('stop');

        var eventEmitter = this.game.events;

        eventEmitter.off('step', this.update);
    }

    setSprite (sprite)
    {
        this.sprite = sprite;
    }

    update (time, delta)
    {
        if (this.sprite)
        {
            this.sprite.x -= 0.2 * delta;

            if (this.sprite.x < 0)
            {
                this.sprite.x = 800;
            }

        }
    }

}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    plugins: {
        global: [
            { key: 'MoveSpritePlugin', plugin: MoveSpritePlugin, start: true }
        ]
    },
    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 ()
{
    let ele = this.add.image(400, 300, 'elephant');

    let plugin = this.plugins.get('MoveSpritePlugin');

    plugin.setSprite(ele);

    this.input.on('pointerup', function (pointer) {

        if (this.plugins.isActive('MoveSpritePlugin'))
        {
            this.plugins.stop('MoveSpritePlugin');
        }
        else
        {
            this.plugins.start('MoveSpritePlugin');
        }

    }, this);
}

Структура пользовательского плагина

Плагин в Phaser должен наследоваться от базового класса Phaser.Plugins.BasePlugin. Это дает доступ к менеджеру плагинов и жизненному циклу. В конструкторе мы вызываем super и можем инициализировать внутренние переменные, например, ссылку на спрайт.

Ключевые методы жизненного цикла: - init(): Вызывается один раз при создании экземпляра плагина. - start(): Запускает активную работу плагина. Здесь обычно подписываются на события игры. - stop(): Останавливает плагин, отписываясь от событий и освобождая ресурсы.

class MoveSpritePlugin extends Phaser.Plugins.BasePlugin {
    constructor(pluginManager) {
        super(pluginManager);
        this.sprite;
    }
    init() {
        console.log('init');
    }
    start() {
        console.log('start');
        var eventEmitter = this.game.events;
        eventEmitter.on('step', this.update, this);
    }
    stop() {
        console.log('stop');
        var eventEmitter = this.game.events;
        eventEmitter.off('step', this.update);
    }
}

Логика обновления и управление спрайтом

Плагин содержит метод update, который будет вызываться на каждом шаге игрового цикла (step), если плагин активен. Внутри мы проверяем, задан ли спрайт, и двигаем его по горизонтали с постоянной скоростью, учитывая delta для независимости от частоты кадров. Когда спрайт уходит за левый край экрана, он возвращается в правую часть.

Метод setSprite позволяет передать плагину любой спрайт для управления извне, что делает плагин универсальным.

setSprite(sprite) {
    this.sprite = sprite;
}

update(time, delta) {
    if (this.sprite) {
        this.sprite.x -= 0.2 * delta;
        if (this.sprite.x < 0) {
            this.sprite.x = 800;
        }
    }
}

Регистрация плагина в конфигурации игры

Чтобы сделать плагин доступным глобально во всех сценах, его нужно указать в конфиге игры в разделе plugins.global. Ключевые параметры: - key: Строковый идентификатор для доступа к плагину. - plugin: Ссылка на класс плагина. - start: Если true, плагин будет автоматически запущен после создания. В нашем примере это так, но позже мы можем его остановить.

const config = {
    type: Phaser.AUTO,
    plugins: {
        global: [
            { key: 'MoveSpritePlugin', plugin: MoveSpritePlugin, start: true }
        ]
    },
    scene: {
        preload: preload,
        create: create
    }
};

Использование плагина в сцене и управление состоянием

В сцене мы сначала загружаем изображение и создаем спрайт. Затем получаем экземпляр плагина по его ключу с помощью this.plugins.get('MoveSpritePlugin') и передаем ему спрайт для управления.

Далее мы настраиваем обработчик клика мыши (pointerup). Внутри проверяем, активен ли плагин в данный момент, с помощью this.plugins.isActive('MoveSpritePlugin'). В зависимости от результата либо останавливаем плагин методом stop, либо запускаем его методом start. Это позволяет toggle-управление (вкл/выкл) движением спрайта по клику.

function create() {
    let ele = this.add.image(400, 300, 'elephant');
    let plugin = this.plugins.get('MoveSpritePlugin');
    plugin.setSprite(ele);

    this.input.on('pointerup', function (pointer) {
        if (this.plugins.isActive('MoveSpritePlugin')) {
            this.plugins.stop('MoveSpritePlugin');
        } else {
            this.plugins.start('MoveSpritePlugin');
        }
    }, this);
}

Что попробовать дальше

Динамическое управление плагинами через start и stop — мощный инструмент для создания модульных и оптимизированных игр. Вы можете расширить пример: добавить несколько плагинов для разных типов движения (например, прыжки или патрулирование), управлять их активностью в зависимости от состояния игрока (бег, полет) или реализовать систему пауз, останавливая все второстепенные процессы. Экспериментируйте с подпиской на другие события, например postUpdate, или добавьте в плагин настройку скорости движения через параметры.