Refactor dnd utility and add drag lifecycle events

Attach pointerup and pointermove listeners to scene.input
for reliable tracking. Emit dragstart, dragmove, and
dragend events alongside drag. Rename relativeX/Y to
deltaX/Y in DragDropEvent and integrate DisposableBag.
This commit is contained in:
hypercross 2026-04-18 23:33:13 +08:00
parent eefcef861a
commit d993d55576
1 changed files with 73 additions and 63 deletions

View File

@ -1,70 +1,80 @@
type PointerRecord = { import { DisposableBag } from "./disposable";
id: number;
x: number; type PointerRecord = {
y: number; id: number;
} x: number;
y: number;
};
export enum DragDropEventType { export enum DragDropEventType {
DOWN, DOWN,
UP, UP,
MOVE, MOVE,
} }
export type DragDropEvent = { export type DragDropEvent = {
type: DragDropEventType, type: DragDropEventType;
relativeX: number; deltaX: number;
relativeY: number; deltaY: number;
} };
export function dragDropEventEffect( export function dragDropEventEffect(
gameObject: Phaser.GameObjects.GameObject, gameObject: Phaser.GameObjects.GameObject,
) { disposables?: DisposableBag,
let down: PointerRecord | null; ): () => void {
let up: PointerRecord | null; let isDragging = false;
let down: PointerRecord | null = null;
function onPointerDown(pointer: Phaser.Input.Pointer) {
down = {
id: pointer.id,
x: pointer.x,
y: pointer.y
}
up = null;
const type = DragDropEventType.DOWN;
const relativeX = pointer.x - down.x;
const relativeY = pointer.y - down.y;
gameObject.emit('drag', {type, relativeX, relativeY});
}
function onPointerUp(pointer: Phaser.Input.Pointer) {
if(!down) return;
up = {
id: pointer.id,
x: pointer.x,
y: pointer.y
}
const type = DragDropEventType.UP;
const relativeX = pointer.x - down.x;
const relativeY = pointer.y - down.y;
gameObject.emit('drag', {type, relativeX, relativeY});
}
function onPointerMove(pointer: Phaser.Input.Pointer) {
if(!down || up) return;
if(down.id !== pointer.id) return;
const type = DragDropEventType.MOVE;
const relativeX = pointer.x - down.x;
const relativeY = pointer.y - down.y;
gameObject.emit('drag', {type, relativeX, relativeY});
}
gameObject.on('pointerdown', onPointerDown); function onPointerDown(pointer: Phaser.Input.Pointer) {
gameObject.on('pointerup', onPointerUp); if (isDragging) return;
gameObject.scene.input.on('pointermove', onPointerMove); isDragging = true;
return function () { down = { id: pointer.id, x: pointer.x, y: pointer.y };
gameObject.off('pointerdown', onPointerDown);
gameObject.off('pointerup', onPointerUp); const event: DragDropEvent = {
gameObject.scene.input.off('pointermove', onPointerMove); type: DragDropEventType.DOWN,
} deltaX: 0,
} deltaY: 0,
};
gameObject.emit("drag", event);
gameObject.emit("dragstart", event);
}
function onPointerUp(pointer: Phaser.Input.Pointer) {
if (!isDragging || !down || pointer.id !== down.id) return;
isDragging = false;
const deltaX = pointer.x - down.x;
const deltaY = pointer.y - down.y;
const event: DragDropEvent = { type: DragDropEventType.UP, deltaX, deltaY };
gameObject.emit("drag", event);
gameObject.emit("dragend", event);
down = null;
}
function onPointerMove(pointer: Phaser.Input.Pointer) {
if (!isDragging || !down || pointer.id !== down.id) return;
const deltaX = pointer.x - down.x;
const deltaY = pointer.y - down.y;
const event: DragDropEvent = {
type: DragDropEventType.MOVE,
deltaX,
deltaY,
};
gameObject.emit("drag", event);
gameObject.emit("dragmove", event);
}
gameObject.on("pointerdown", onPointerDown);
gameObject.scene.input.on("pointerup", onPointerUp);
gameObject.scene.input.on("pointermove", onPointerMove);
const dispose = () => {
gameObject.off("pointerdown", onPointerDown);
gameObject.scene.input.off("pointerup", onPointerUp);
gameObject.scene.input.off("pointermove", onPointerMove);
};
disposables?.add(dispose);
return dispose;
}