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

Хранение и управление дополнительными свойствами объектов — ключевая задача в разработке игр. В Phaser для этого есть встроенная система Data Manager, позволяющая присвоить любому игровому объекту (спрайту, тексту, изображению) пользовательские данные и отслеживать их изменение в реальном времени. Эта статья покажет, как использовать методы `setData()`, `getData()` и событие `changedata` для создания динамических объектов, которые реагируют на игровые события. Вы научитесь привязывать к предметам уровень, стоимость, владельца и обновлять интерфейс автоматически при их изменении.

Версия 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/');
        this.load.image('gem', 'assets/sprites/gem.png');
    }

    create ()
    {
        const text = this.add.text(350, 270, '', { font: '16px Courier', fill: '#00ff00' });
        const gem = this.add.image(300, 300, 'gem');

        //  Store some data about this Gem:
        gem.setData({ name: 'Red Gem Stone', level: 2, owner: 'Link', 'gold': 50 });

        //  Whenever a data value is updated the `changedata` event is fired and we listen for it:
        gem.on('changedata', function (gameObject, key, value) {
            text.setText([
                'Name: ' + gem.getData('name'),
                'Level: ' + gem.getData('level'),
                'Value: ' + gem.getData('gold') + ' gold',
                'Owner: ' + gem.getData('owner')
            ]);
        });

        //  Change the 'value' property when the mouse is clicked
        this.input.on('pointerdown', function () {
            gem.data.values.gold += 50;
            if (gem.data.values.gold % 200 === 0)
            {
                gem.data.values.level++;
            }
        });
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка сцены и загрузка ассетов

В методе preload() мы устанавливаем базовый URL для загрузки ресурсов и загружаем изображение драгоценного камня. В create() создаём текстовый объект для отображения данных и сам спрайт камня.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('gem', 'assets/sprites/gem.png');
}

create ()
{
    const text = this.add.text(350, 270, '', { font: '16px Courier', fill: '#00ff00' });
    const gem = this.add.image(300, 300, 'gem');
}

Присвоение данных объекту с помощью setData

Метод setData() объекта gem позволяет установить несколько пользовательских свойств одновременно. Мы передаём ему объект с ключами name, level, owner и gold. Эти данные сохраняются во внутреннем хранилище объекта и не влияют на его визуальное отображение по умолчанию.

gem.setData({ name: 'Red Gem Stone', level: 2, owner: 'Link', 'gold': 50 });

Доступ к этим значениям впоследствии можно получить через gem.getData('key') или напрямую через gem.data.values.key.

Реакция на изменение данных через событие changedata

Phaser генерирует событие changedata каждый раз, когда изменяется любое свойство, установленное через setData(). Мы подписываемся на это событие с помощью gem.on(). В обработчике события мы обновляем текстовый объект, выводя актуальные значения всех интересующих нас свойств.

gem.on('changedata', function (gameObject, key, value) {
    text.setText([
        'Name: ' + gem.getData('name'),
        'Level: ' + gem.getData('level'),
        'Value: ' + gem.getData('gold') + ' gold',
        'Owner: ' + gem.getData('owner')
    ]);
});

Обратите внимание: обработчик срабатывает при изменении любого свойства, но текст обновляется полностью, показывая все данные. Параметры key и value в функции содержат ключ и новое значение изменённого свойства.

Изменение данных по игровому событию

В примере данные изменяются по клику мыши. Мы вешаем обработчик на событие pointerdown от this.input. Внутри обработчика мы напрямую обращаемся к объекту gem.data.values для изменения свойств gold и level.

this.input.on('pointerdown', function () {
    gem.data.values.gold += 50;
    if (gem.data.values.gold % 200 === 0)
    {
        gem.data.values.level++;
    }
});

Каждое изменение gold или level автоматически запускает событие changedata, которое, как мы настроили ранее, обновляет текст на экране. Это создаёт замкнутую и реактивную систему.

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

Система Data Manager в Phaser предоставляет элегантный способ расширить стандартные игровые объекты вашим контекстом. Вы можете хранить в них здоровье, урон, инвентарь, статусы эффектов — всё что угодно. Для экспериментов попробуйте: создать инвентарь, где предметы имеют вес и цену; реализовать систему прокачки, где изменение уровня одного объекта влияет на свойства другого; или привязать изменение данных к таймеру, а не к клику мыши.