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

В Phaser 3 управление вводом с мыши интуитивно понятно, но обработка правой кнопки требует особого подхода. Стандартное событие `'pointerdown'` срабатывает для всех кнопок, и чтобы отличить правый клик от левого, нужно использовать методы объекта `Pointer`. В этой статье мы разберем пример, который показывает, как отключить контекстное меню браузера и создать разную реакцию на короткий и долгий клик левой и правой кнопкой мыши, что полезно для игровых интерфейсов и интерактивных элементов.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    text;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('logo', 'assets/sprites/phaser.png');
        this.load.image('asuna', 'assets/sprites/asuna_by_vali233.png');
        this.load.image('disk', 'assets/sprites/oz_pov_melting_disk.png');
        this.load.image('tree', 'assets/sprites/palm-tree-left.png');
    }

    create ()
    {
        this.text = this.add.text(10, 10, '', { fill: '#00ff00' }).setDepth(1);

        this.input.mouse.disableContextMenu();

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

            if (pointer.rightButtonDown())
            {
                if (pointer.getDuration() > 500)
                {
                    this.add.image(pointer.x, pointer.y, 'disk');
                }
                else
                {
                    this.add.image(pointer.x, pointer.y, 'asuna');
                }
            }
            else
            if (pointer.getDuration() > 500)
            {
                this.add.image(pointer.x, pointer.y, 'tree');
            }
            else
            {
                this.add.image(pointer.x, pointer.y, 'logo');
            }

        }, this);
    }

    update ()
    {
        const pointer = this.input.activePointer;

        this.text.setText([
            `x: ${pointer.worldX}`,
            `y: ${pointer.worldY}`,
            `isDown: ${pointer.isDown}`,
            `rightButtonDown: ${pointer.rightButtonDown()}`
        ]);
    }
}

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

const game = new Phaser.Game(config);

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

Класс Example расширяет Phaser.Scene. В методе preload() задается базовый URL и загружаются четыре спрайта, которые будут использоваться в качестве визуальных маркеров для разных типов кликов.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('logo', 'assets/sprites/phaser.png');
this.load.image('asuna', 'assets/sprites/asuna_by_vali233.png');
this.load.image('disk', 'assets/sprites/oz_pov_melting_disk.png');
this.load.image('tree', 'assets/sprites/palm-tree-left.png');

Отключение контекстного меню браузера

В методе create() первым делом создается текстовый объект для отладки. Затем вызывается критически важная для работы с правой кнопкой мыши строка кода:

this.input.mouse.disableContextMenu();

Этот метод отключает стандартное контекстное меню браузера, которое появляется при клике правой кнопкой мыши. Без этого вызова браузер будет перехватывать событие, и наш обработчик 'pointerdown' для правой кнопки может не сработать или сработать некорректно.

Обработчик события pointerdown

Основная логика обработки кликов заключена в обработчике события 'pointerdown'. Внутри функции мы получаем объект pointer и анализируем его состояние.

this.input.on('pointerdown', function (pointer)
{
    if (pointer.rightButtonDown())
    {
        if (pointer.getDuration() > 500)
        {
            this.add.image(pointer.x, pointer.y, 'disk');
        }
        else
        {
            this.add.image(pointer.x, pointer.y, 'asuna');
        }
    }
    else
    if (pointer.getDuration() > 500)
    {
        this.add.image(pointer.x, pointer.y, 'tree');
    }
    else
    {
        this.add.image(pointer.x, pointer.y, 'logo');
    }
}, this);

Логика ветвления следующая: 1. Сначала проверяется, нажата ли правая кнопка с помощью метода pointer.rightButtonDown(). 2. Если да, то далее проверяется длительность нажатия методом pointer.getDuration(). Если клик был долгим (>500 мс), появляется спрайт 'disk', иначе — спрайт 'asuna'. 3. Если правая кнопка не нажата (значит, это левая кнопка или касание), проверяется длительность нажатия. Долгий клик создает спрайт 'tree', короткий — спрайт 'logo'.

Обратите внимание на третий аргумент this при подписке на событие. Он задает контекст выполнения callback-функции, чтобы внутри нее this ссылался на экземпляр сцены, и мы могли вызывать this.add.image.

Отладочная информация в реальном времени

Метод update() вызывается на каждом кадре и обновляет текстовую панель актуальными данными об активном указателе. this.input.activePointer — это главный указатель (мышь или первое касание).

const pointer = this.input.activePointer;

this.text.setText([
    `x: ${pointer.worldX}`,
    `y: ${pointer.worldY}`,
    `isDown: ${pointer.isDown}`,
    `rightButtonDown: ${pointer.rightButtonDown()}`
]);

Здесь отображаются: - Координаты указателя в мировой системе координат (worldX, worldY). - Общее состояние нажатия кнопки или касания (isDown). - Состояние конкретно правой кнопки мыши (rightButtonDown()).

Конфигурация и запуск игры

Стандартная конфигурация объекта игры Phaser.Game. В ней указываются размеры холста, тип рендерера, идентификатор родительского DOM-элемента и стартовая сцена.

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

const game = new Phaser.Game(config);

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

Пример демонстрирует ключевые аспекты работы с правой кнопкой мыши в Phaser 3: обязательное отключение контекстного меню, проверку кнопки через rightButtonDown() и комбинирование этой проверки с другими свойствами указателя, такими как длительность нажатия. Для экспериментов попробуйте добавить обработку средней кнопки мыши (pointer.middleButtonDown()), реализовать перетаскивание объектов правой кнопкой или создать контекстное меню игры, которое появляется при долгом правом клике.