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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    graphics;

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

    create ()
    {
        //  We need 2 extra pointers, as we only get 1 by default
        this.input.addPointer(2);

        const sprite1 = this.add.sprite(400, 100, 'logo').setInteractive({ draggable: true });

        sprite1.on('drag', function (pointer, dragX, dragY)
        {

            this.x = dragX;
            this.y = dragY;

        });

        const sprite2 = this.add.sprite(400, 300, 'logo').setInteractive({ draggable: true });

        sprite2.on('drag', function (pointer, dragX, dragY)
        {

            this.x = dragX;
            this.y = dragY;

        });

        const sprite3 = this.add.sprite(400, 500, 'logo').setInteractive({ draggable: true });

        sprite3.on('drag', function (pointer, dragX, dragY)
        {

            this.x = dragX;
            this.y = dragY;

        });

        this.graphics = this.add.graphics();

        this.add.text(10, 10, 'Multi touch drag test', { font: '16px Courier', fill: '#000000' });
    }

    update ()
    {
        if (this.input.pointer1.isDown || this.input.pointer2.isDown || this.input.pointer3.isDown)
        {
            this.graphics.clear();
        }

        this.graphics.fillStyle(0xff0000, 1);
        this.graphics.fillRect(this.input.pointer1.x, this.input.pointer1.y, 44, 44);

        this.graphics.fillStyle(0x00ff00, 1);
        this.graphics.fillRect(this.input.pointer2.x, this.input.pointer2.y, 44, 44);

        this.graphics.fillStyle(0x0000ff, 1);
        this.graphics.fillRect(this.input.pointer3.x, this.input.pointer3.y, 44, 44);
    }
}

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

const game = new Phaser.Game(config);

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

По умолчанию Phaser создает один основной указатель для ввода (например, для мыши или первого касания). Для обработки мультитача необходимо добавить дополнительные указатели в систему ввода сцены. Это делается в методе create.

this.input.addPointer(2);

Вызов метода this.input.addPointer(2) добавляет в систему ввода еще два указателя. Теперь у нас есть три доступных указателя: pointer1, pointer2 и pointer3. Их состояние (координаты, нажатие) можно отслеживать в любой момент, например, в методе update.

Создание и настройка перетаскиваемых спрайтов

Чтобы спрайт можно было перетаскивать, его нужно сделать интерактивным с опцией draggable: true. Затем на объект спрайта вешается обработчик события drag, который будет вызываться при каждом перемещении указателя, удерживающего этот спрайт.

const sprite1 = this.add.sprite(400, 100, 'logo').setInteractive({ draggable: true });

sprite1.on('drag', function (pointer, dragX, dragY) {
    this.x = dragX;
    this.y = dragY;
});

Внутри функции-обработчика this ссылается на сам спрайт (sprite1). Параметры dragX и dragY содержат новые координаты, куда система ввода предлагает переместить спрайт. Присваивая эти значения свойствам `xиy`, мы заставляем спрайт следовать за указателем. Этот процесс повторяется для каждого из трех спрайтов в примере, делая их независимо перетаскиваемыми.

Визуализация активных точек касания

Для наглядной демонстрации работы мультитача в методе update происходит отрисовка трех цветных квадратов, которые следуют за координатами каждого указателя. Это помогает понять, какие касания в данный момент активны.

if (this.input.pointer1.isDown || this.input.pointer2.isDown || this.input.pointer3.isDown) {
    this.graphics.clear();
}

Сначала проверяется условие: если хотя бы один из указателей нажат (isDown), то canvas объекта Graphics очищается. Это необходимо, чтобы квадраты не оставляли шлейф при движении.

Затем для каждого указателя рисуется квадрат разного цвета по его текущим координатам.

this.graphics.fillStyle(0xff0000, 1);
this.graphics.fillRect(this.input.pointer1.x, this.input.pointer1.y, 44, 44);

this.input.pointer1.x и this.input.pointer1.y — это текущие координаты первого указателя. Аналогичный код выполняется для pointer2 (зеленый) и pointer3 (синий). Таким образом, на экране всегда видны последние позиции всех трех точек ввода.

Ключевые объекты API Phaser

В этом примере используются несколько важных объектов и свойств Phaser для работы с вводом:

*   `this.input`: Главный объект управления вводом сцены.
*   `this.input.addPointer(count)`: Метод для добавления дополнительных указателей.
*   `this.input.pointer1`, `pointer2`, `pointer3`: Объекты, хранящие состояние конкретных указателей.
*   `pointer.isDown`: Свойство, указывающее, нажат ли указатель в данный момент.
*   `pointer.x`, `pointer.y`: Текущие координаты указателя.
*   `sprite.setInteractive(config)`: Метод для включения интерактивности у игрового объекта с опциями, такими как `draggable: true`.
*   `sprite.on('drag', callback)`: Подписка на событие перетаскивания для конкретного спрайта.

Использование этих API позволяет гибко управлять мультитач-взаимодействиями в игре.

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

Пример наглядно показывает, что реализация базового мультитач-перетаскивания в Phaser — это прямое использование встроенного API. Система сама обрабатывает распределение событий между указателями и объектами. Для экспериментов попробуйте: изменить логику в событии drag, чтобы добавлять инерцию или ограничивать область перетаскивания; использовать разные типы жестов (например, pinch для масштабирования); или привязать перетаскивание не к спрайтам, а к камере, реализовав управление игровым миром двумя пальцами.