В библиотеке Phaser система drag and drop
реализована через встроенный Input Plugin, который
позволяет делать объекты интерактивными и реагировать на события
перетаскивания. Основные события — это dragstart,
drag и dragend. Они позволяют отслеживать
начало, процесс и завершение перемещения объекта.
Для работы с перетаскиванием необходимо сначала включить интерактивность объекта и активировать для него поддержку drag:
this.sprite.setInteractive({ draggable: true });
Параметр draggable: true указывает Phaser, что объект
можно перетаскивать. После этого объект можно подключать к событиям
drag.
dragstart вызывается один раз в момент
начала перетаскивания объекта. Событие передает два основных параметра:
сам объект и указатель (pointer), который инициировал
перетаскивание.
this.input.on('dragstart', (pointer, gameObject) => {
gameObject.setTint(0xff0000); // Изменение цвета для визуальной индикации начала перетаскивания
});
Особенности dragstart:
drag срабатывает каждый раз, когда
объект перемещается. Оно передает три аргумента: указатель, объект и
смещение (dragX, dragY).
this.input.on('drag', (pointer, gameObject, dragX, dragY) => {
gameObject.x = dragX;
gameObject.y = dragY;
});
Ключевые моменты:
dragX = Phaser.Math.Clamp(dragX, 0, this.sys.game.config.width);
dragY = Phaser.Math.Clamp(dragY, 0, this.sys.game.config.height);
gameObject.setPosition(dragX, dragY);
dragend срабатывает один раз при
отпускании объекта. Передаются указатель и объект, а также сведения о
том, был ли drag успешно завершен.
this.input.on('dragend', (pointer, gameObject, dropped) => {
gameObject.clearTint(); // Снятие визуального выделения
if (!dropped) {
gameObject.x = gameObject.input.dragStartX;
gameObject.y = gameObject.input.dragStartY; // Возврат в начальную позицию
}
});
Особенности dragend:
Drop zone — это область, куда можно сбрасывать перетаскиваемый
объект. Для создания drop zone используется метод
this.add.zone(x, y, width, height) и установка
интерактивности:
let zone = this.add.zone(400, 300, 200, 150).setRectangleDropZone(200, 150);
zone.setName('targetZone');
Для отслеживания успешного броска объекта в drop zone применяется
событие drop:
this.input.on('drop', (pointer, gameObject, dropZone) => {
gameObject.x = dropZone.x;
gameObject.y = dropZone.y;
});
Принципы работы:
dragend полезно для возврата объекта, если он
не был брошен в drop zone (dropped = false).drag
вызывается каждый кадр, поэтому тяжелая логика внутри него может снижать
FPS. Лучше вычисления ограничивать минимально необходимыми
действиями.Phaser.Math.Clamp или методы
snap-to-grid (gameObject.setSnap).this.input.on('drag', (pointer, gameObject, dragX, dragY) => {
const gridSize = 32;
gameObject.x = Math.round(dragX / gridSize) * gridSize;
gameObject.y = Math.round(dragY / gridSize) * gridSize;
});
this.input.on('drag', (pointer, gameObject) => {
let nearestTarget = this.targets.getChildren().reduce((prev, curr) => {
let prevDist = Phaser.Math.Distance.Between(gameObject.x, gameObject.y, prev.x, prev.y);
let currDist = Phaser.Math.Distance.Between(gameObject.x, gameObject.y, curr.x, curr.y);
return currDist < prevDist ? curr : prev;
});
gameObject.x = nearestTarget.x;
gameObject.y = nearestTarget.y;
});
this.input.on('drop', (pointer, gameObject, dropZone) => {
this.tweens.add({
targets: gameObject,
x: dropZone.x,
y: dropZone.y,
duration: 300,
ease: 'Power2'
});
});
Эти подходы позволяют создавать интерактивные, отзывчивые интерфейсы и игры, где объекты можно перетаскивать, точно размещать и визуально отслеживать действия пользователя.