Extract input module
This commit is contained in:
167
src/input.js
Normal file
167
src/input.js
Normal file
@@ -0,0 +1,167 @@
|
||||
(() => {
|
||||
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 };
|
||||
})();
|
||||
Reference in New Issue
Block a user