168 lines
4.2 KiB
JavaScript
168 lines
4.2 KiB
JavaScript
(() => {
|
|
const { Query, Constraint, World, Vector } = Matter;
|
|
|
|
const create = ({
|
|
render,
|
|
world,
|
|
balls,
|
|
boundaries,
|
|
chain,
|
|
config,
|
|
getCurrentScene,
|
|
isPaused,
|
|
isLevelWon,
|
|
isGameOver,
|
|
getMaxLinkDistance,
|
|
setHighlight,
|
|
removeLastFromChain,
|
|
addToChain,
|
|
finishChain,
|
|
updateHud,
|
|
}) => {
|
|
let dragConstraint = null;
|
|
|
|
const getPointerPosition = (evt) => {
|
|
const rect = render.canvas.getBoundingClientRect();
|
|
const clientX = evt.touches ? evt.touches[0].clientX : evt.clientX;
|
|
const clientY = evt.touches ? evt.touches[0].clientY : evt.clientY;
|
|
return {
|
|
x: clientX - rect.left,
|
|
y: clientY - rect.top,
|
|
};
|
|
};
|
|
|
|
const getDraggableBody = (point) => {
|
|
const draggables = [
|
|
...boundaries.filter((b) => b.plugin?.draggable),
|
|
...balls.filter((b) => b.plugin?.draggable),
|
|
];
|
|
const hits = Query.point(draggables, point);
|
|
return hits[0];
|
|
};
|
|
|
|
const pickBody = (point) => {
|
|
const hits = Query.point(balls, point);
|
|
return hits[0];
|
|
};
|
|
|
|
const startDrag = (body, point) => {
|
|
endDrag();
|
|
dragConstraint = Constraint.create({
|
|
pointA: point,
|
|
bodyB: body,
|
|
stiffness: 0.2,
|
|
damping: 0.3,
|
|
render: { visible: false },
|
|
});
|
|
World.add(world, dragConstraint);
|
|
};
|
|
|
|
const updateDrag = (point) => {
|
|
if (!dragConstraint) return;
|
|
dragConstraint.pointA = point;
|
|
};
|
|
|
|
const endDrag = () => {
|
|
if (dragConstraint) {
|
|
World.remove(world, dragConstraint);
|
|
dragConstraint = null;
|
|
}
|
|
};
|
|
|
|
const handlePointerDown = (evt) => {
|
|
if (isGameOver() || isPaused() || isLevelWon()) return;
|
|
const point = getPointerPosition(evt);
|
|
const dragTarget = getDraggableBody(point);
|
|
if (dragTarget) {
|
|
startDrag(dragTarget, point);
|
|
return;
|
|
}
|
|
const body = pickBody(point);
|
|
if (!body) return;
|
|
const scene = getCurrentScene();
|
|
if (!scene?.config?.relaxMode) {
|
|
chain.color = body.plugin.color;
|
|
} else {
|
|
chain.color = body.plugin.color;
|
|
}
|
|
chain.active = true;
|
|
chain.bodies = [body];
|
|
chain.constraints = [];
|
|
chain.pointer = point;
|
|
setHighlight(body, true);
|
|
updateHud();
|
|
};
|
|
|
|
const handlePointerMove = (evt) => {
|
|
if (dragConstraint) {
|
|
updateDrag(getPointerPosition(evt));
|
|
return;
|
|
}
|
|
if (!chain.active) return;
|
|
if (isGameOver() || isPaused() || isLevelWon()) return;
|
|
const point = getPointerPosition(evt);
|
|
chain.pointer = point;
|
|
const body = pickBody(point);
|
|
if (!body) return;
|
|
const alreadyInChain = chain.bodies.includes(body);
|
|
if (alreadyInChain) {
|
|
const targetIndex = chain.bodies.indexOf(body);
|
|
if (chain.bodies.length > 1 && targetIndex === chain.bodies.length - 2) {
|
|
removeLastFromChain();
|
|
}
|
|
return;
|
|
}
|
|
const scene = getCurrentScene();
|
|
if (!scene?.config?.relaxMode && body.plugin.color !== chain.color) return;
|
|
const maxLinkDist = getMaxLinkDistance();
|
|
const dist = Vector.magnitude(
|
|
Vector.sub(chain.bodies[chain.bodies.length - 1].position, body.position),
|
|
);
|
|
if (dist > maxLinkDist) return;
|
|
addToChain(body);
|
|
};
|
|
|
|
const handlePointerUp = () => {
|
|
if (dragConstraint) {
|
|
endDrag();
|
|
return;
|
|
}
|
|
finishChain(chain.pointer);
|
|
};
|
|
|
|
render.canvas.addEventListener("mousedown", handlePointerDown);
|
|
render.canvas.addEventListener("mousemove", handlePointerMove);
|
|
window.addEventListener("mouseup", handlePointerUp);
|
|
render.canvas.addEventListener(
|
|
"touchstart",
|
|
(e) => {
|
|
e.preventDefault();
|
|
handlePointerDown(e);
|
|
},
|
|
{ passive: false },
|
|
);
|
|
render.canvas.addEventListener(
|
|
"touchmove",
|
|
(e) => {
|
|
e.preventDefault();
|
|
handlePointerMove(e);
|
|
},
|
|
{ passive: false },
|
|
);
|
|
render.canvas.addEventListener(
|
|
"touchend",
|
|
(e) => {
|
|
e.preventDefault();
|
|
handlePointerUp(e);
|
|
},
|
|
{ passive: false },
|
|
);
|
|
|
|
return {
|
|
endDrag,
|
|
};
|
|
};
|
|
|
|
window.PhysilinksInput = { create };
|
|
})();
|