Improved drag handles code and remove dependency from mouse object.

This commit is contained in:
Davide Tantillo 2025-11-26 16:23:49 +01:00
parent a641916750
commit e98c376963

View File

@ -130,9 +130,11 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
this.x + this.propOffsetX, this.x + this.propOffsetX,
this.y + this.propOffsetY, this.y + this.propOffsetY,
this.angle + this.propOffsetAngle); this.angle + this.propOffsetAngle);
skeleton.updateWorldTransform(physicsMode);
this.updateHandles(skeleton, matrix); this.updateHandles(skeleton, matrix);
skeleton.updateWorldTransform(physicsMode);
this.updateBoneFollowers(); this.updateBoneFollowers();
} }
@ -164,7 +166,9 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
/* /*
* Drag handles * Drag handles
*/ */
private touchDown = false;
private touchX = 0;
private touchY = 0;
public addDragHandle (type: 0 | 1, name: string, radius = 10, debug = false) { public addDragHandle (type: 0 | 1, name: string, radius = 10, debug = false) {
if (type === 0) { if (type === 0) {
const bone = this.getBone(name); const bone = this.getBone(name);
@ -175,6 +179,36 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
if (!slot) return; if (!slot) return;
this.dragHandles.add({ slot, bone: slot.bone, debug, radius, offsetX: 0, offsetY: 0 }); this.dragHandles.add({ slot, bone: slot.bone, debug, radius, offsetX: 0, offsetY: 0 });
} }
if (this.dragHandles.size === 1) {
this.touchDown = false;
this.runtime.addEventListener("pointerdown", this.dragHandleDown);
this.runtime.addEventListener("pointermove", this.dragHandleMove);
this.runtime.addEventListener("pointerup", this.dragHandleUp);
}
}
private dragHandleDown = (event: ConstructPointerEvent) => {
if (event.button !== 0) return;
this.touchDown = true;
this.touchX = event.clientX;
this.touchY = event.clientY;
};
private dragHandleMove = (event: ConstructPointerEvent) => {
if (!this.touchDown) return;
this.touchX = event.clientX;
this.touchY = event.clientY;
}
private dragHandleUp = (event: ConstructPointerEvent) => {
if (event.button === 0) this.touchDown = false;
}
private dragHandleDispose () {
this.runtime.removeEventListener("pointerdown", this.dragHandleDown);
this.runtime.removeEventListener("pointermove", this.dragHandleMove);
this.runtime.removeEventListener("pointerup", this.dragHandleUp);
} }
public removeDragHandle (type: 0 | 1, name: string) { public removeDragHandle (type: 0 | 1, name: string) {
@ -185,7 +219,7 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
for (const handle of this.dragHandles) { for (const handle of this.dragHandles) {
if (handle.bone === bone && !handle.slot) { if (handle.bone === bone && !handle.slot) {
this.dragHandles.delete(handle); this.dragHandles.delete(handle);
return; break;
} }
} }
} else { } else {
@ -195,60 +229,51 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
for (const handle of this.dragHandles) { for (const handle of this.dragHandles) {
if (handle.slot === slot) { if (handle.slot === slot) {
this.dragHandles.delete(handle); this.dragHandles.delete(handle);
return; break;
} }
} }
} }
if (this.dragHandles.size === 0) this.dragHandleDispose();
} }
private updateHandles (skeleton: Skeleton, matrix: C3Matrix) { private updateHandles (skeleton: Skeleton, matrix: C3Matrix) {
if (this.dragHandles.size === 0) return; if (this.dragHandles.size === 0) return;
// accessing mouse without having a mouse object will throw an error const { touchDown } = this;
let mouse: IMouseObjectType; if (!touchDown) {
try { if (this.prevLeftClickDown) {
mouse = this.runtime.mouse; this.prevLeftClickDown = false;
} catch (_) { for (const handleObject of this.dragHandles) handleObject.dragging = false;
}
return; return;
} }
const isLeftClickDown = mouse.isMouseButtonDown(0); const { touchX, touchY } = this;
if (this.dragHandles.size <= 0) {
this.prevLeftClickDown = isLeftClickDown;
return;
}
if (!isLeftClickDown) {
this.prevLeftClickDown = false;
for (const handleObject of this.dragHandles) handleObject.dragging = false;
return;
}
const [mx, my] = mouse.getMousePosition();
for (const handleObject of this.dragHandles) { for (const handleObject of this.dragHandles) {
const bone = handleObject.bone; const bone = handleObject.bone;
const boneApplied = bone.applied;
if (handleObject.dragging) { if (handleObject.dragging) {
const pose = bone.pose;
if (bone.parent) { if (bone.parent) {
const { x, y } = matrix.gameToBone(mx - handleObject.offsetX, my - handleObject.offsetY, bone); const { x, y } = matrix.gameToBone(touchX - handleObject.offsetX, touchY - handleObject.offsetY, bone);
boneApplied.x = x; pose.x = x;
boneApplied.y = y; pose.y = y;
} else { } else {
const { x, y } = matrix.gameToSkeleton(mx - handleObject.offsetX, my - handleObject.offsetY); const { x, y } = matrix.gameToSkeleton(touchX - handleObject.offsetX, touchY - handleObject.offsetY);
boneApplied.x = x / skeleton.scaleX; pose.x = x / skeleton.scaleX;
boneApplied.y = -y / skeleton.scaleY * spine.Skeleton.yDir; pose.y = -y / skeleton.scaleY * spine.Skeleton.yDir;
} }
} else if (!this.prevLeftClickDown) { } else if (!this.prevLeftClickDown) {
const { x, y } = matrix.gameToSkeleton(mx, my); const applied = bone.applied;
const { x, y } = matrix.gameToSkeleton(touchX, touchY);
const inside = handleObject.slot const inside = handleObject.slot
? this.isInsideSlot(x, y, handleObject.slot, true) ? this.isInsideSlot(x, y, handleObject.slot, true)
: this.inRadius(x, y, boneApplied.worldX, boneApplied.worldY, handleObject.radius); : this.inRadius(x, y, applied.worldX, applied.worldY, handleObject.radius);
if (inside) { if (inside) {
handleObject.dragging = true; handleObject.dragging = true;
handleObject.offsetX = x - boneApplied.worldX; handleObject.offsetX = x - applied.worldX;
handleObject.offsetY = y - boneApplied.worldY; handleObject.offsetY = y - applied.worldY;
} }
} }
} }