О чем этот пример
Стандартное перетаскивание в Phaser 3 работает 'из коробки', но часто возникает вопрос: как корректно перетаскивать объекты, которые были повёрнуты или масштабированы? В примере показано, что API инпут-системы Phaser корректно обрабатывает трансформации объекта. Вам не нужно вручную пересчитывать координаты — система `drag` уже предоставляет правильные значения `dragX` и `dragY`. Это полезно для создания интерактивных панелей, карт, пазлов или инвентаря, где элементы могут быть произвольно трансформированы.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
}
create ()
{
const image = this.add.image(400, 300, 'cards', 'clubsKing');
// Rotate it
image.setAngle(45);
// Scale it
image.setScale(2);
// Make interactive
image.setInteractive();
// Make draggable
this.input.setDraggable(image);
this.input.on('dragstart', function (pointer, gameObject)
{
this.children.bringToTop(gameObject);
}, this);
this.input.on('drag', (pointe, gameObject, dragX, dragY) =>
{
gameObject.x = dragX;
gameObject.y = dragY;
});
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка и трансформация объекта
В методе create создаётся спрайт, после чего к нему применяются два ключевых преобразования: поворот на 45 градусов и увеличение масштаба в 2 раза. Эти операции изменяют визуальное представление, но не ломают систему взаимодействия.
const image = this.add.image(400, 300, 'cards', 'clubsKing');
image.setAngle(45);
image.setScale(2);
Далее объекту необходимо добавить интерактивность и разрешить перетаскивание. Без этого система ввода не будет на него реагировать.
image.setInteractive();
this.input.setDraggable(image);
Обработка начала перетаскивания
При старте перетаскивания (dragstart) часто требуется визуально выделить активный объект, например, переместив его на передний план. В примере для этого используется метод this.children.bringToTop(gameObject). Обратите внимание, что обработчик привязан к контексту сцены (this) с помощью третьего аргумента.
this.input.on('dragstart', function (pointer, gameObject) {
this.children.bringToTop(gameObject);
}, this);
Эта строчка гарантирует, что перетаскиваемая карта будет поверх других элементов, если они есть.
Обработка процесса перетаскивания
Самое важное происходит в обработчике события drag. Система ввода Phaser автоматически рассчитывает корректные координаты (dragX, dragY) с учётом всех применённых к объекту трансформаций (поворота и масштаба). Вам остаётся только присвоить их объекту. В примере используется стрелочная функция, которая автоматически сохраняет контекст сцены.
this.input.on('drag', (pointer, gameObject, dragX, dragY) => {
gameObject.x = dragX;
gameObject.y = dragY;
});
Благодаря этой логике объект будет плавно и точно следовать за курсором, как если бы он не был повёрнут или увеличен.
Конфигурация игры и сцены
Весь функционал упакован в конфигурацию игры, где указывается тип рендерера, размеры холста и класс основной сцены.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Phaser 3 предоставляет отличную абстракцию для перетаскивания, которая избавляет разработчика от ручных расчётов геометрии. Для экспериментов попробуйте
- Добавить физическое тело объекту и посмотреть, как перетаскивание взаимодействует с движком физики (Arcade или Matter)
- Реализовать 'привязку' объекта к сетке при отпускании
- Создать контейнер с несколькими трансформированными объектами и реализовать логику выбора поверхностного объекта под курсором
