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

Механика перетаскивания объектов — одна из базовых и часто используемых в играх и интерактивных приложениях. Будь то пазлы, головоломки, редакторы уровней или стратегии, возможность перемещать элементы мышью или касанием пальца значительно улучшает пользовательский опыт. В Phaser 3 реализовать это проще, чем кажется, благодаря встроенной системе Input. Эта статья покажет, как за несколько строк кода добавить плавное и отзывчивое перетаскивание любому спрайту или игровому объекту.

Версия 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('bg', 'assets/skies/gradient29.png');
        this.load.image('char', 'assets/pics/nayuki.png');
    }

    create ()
    {
        this.add.image(400, 300, 'bg');

        this.add.text(16, 16, 'Drag the Sprite').setFontSize(24).setShadow(1, 1);

        const sprite = this.add.sprite(400, 300, 'char');

        sprite.setInteractive({ draggable: true });

        sprite.on('drag', (pointer, dragX, dragY) => sprite.setPosition(dragX, dragY));
    }
}

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

const game = new Phaser.Game(config);

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

Работа начинается с создания класса сцены, унаследованного от Phaser.Scene. В методе preload мы загружаем необходимые изображения. В данном примере это фон (bg) и изображение персонажа (char).

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('bg', 'assets/skies/gradient29.png');
    this.load.image('char', 'assets/pics/nayuki.png');
}

Создание объектов и настройка интерактивности

В методе create мы размещаем фон и текстовую подсказку. Ключевой шаг — создание спрайта и вызов метода setInteractive с опцией { draggable: true }. Это сообщает Phaser, что данный объект должен реагировать на события ввода и его можно перетаскивать.

create ()
{
    this.add.image(400, 300, 'bg');
    this.add.text(16, 16, 'Drag the Sprite').setFontSize(24).setShadow(1, 1);
    const sprite = this.add.sprite(400, 300, 'char');
    sprite.setInteractive({ draggable: true });
}

Обработка события перетаскивания

Чтобы объект действительно начал двигаться за указателем, необходимо подписаться на событие 'drag'. Это событие генерируется непрерывно во время процесса перетаскивания. В обработчик передаются координаты указателя (dragX, dragY), которые мы используем для обновления позиции спрайта с помощью setPosition.

sprite.on('drag', (pointer, dragX, dragY) => sprite.setPosition(dragX, dragY));

Таким образом, в каждом кадре во время перетаскивания позиция спрайта синхронизируется с позицией курсора мыши или касания.

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

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

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

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

Всего три шага: setInteractive({ draggable: true }), подписка на событие 'drag' и обновление позиции — и механика перетаскивания готова. Это основа, которую можно развивать. Попробуйте ограничить область перетаскивания, добавить физическое тело объекту для столкновений или реализовать "привязку" к сетке при отпускании. Также можно использовать события 'dragstart' и 'dragend' для визуальной обратной связи, например, изменения масштаба или прозрачности спрайта.