Fix color matching and blob types
This commit is contained in:
82
main.js
82
main.js
@@ -108,6 +108,7 @@
|
||||
let levelWon = false;
|
||||
let timerEndMs = null;
|
||||
let lastTimerDisplay = null;
|
||||
let dragConstraint = null;
|
||||
|
||||
const makeStorageKey = (sceneId) => `physilinks-highscore-${sceneId}`;
|
||||
|
||||
@@ -345,6 +346,7 @@
|
||||
score = 0;
|
||||
clearedCount = 0;
|
||||
clearedByColor = {};
|
||||
endDrag();
|
||||
const winCond = currentScene?.config?.winCondition;
|
||||
if (winCond?.type === "timer") {
|
||||
const duration = winCond.durationSec ?? 120;
|
||||
@@ -564,6 +566,39 @@
|
||||
return hits[0];
|
||||
};
|
||||
|
||||
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 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 getPointerPosition = (evt) => {
|
||||
const rect = render.canvas.getBoundingClientRect();
|
||||
const clientX = evt.touches ? evt.touches[0].clientX : evt.clientX;
|
||||
@@ -577,10 +612,20 @@
|
||||
const handlePointerDown = (evt) => {
|
||||
if (gameOver || isPaused || levelWon) return;
|
||||
const point = getPointerPosition(evt);
|
||||
const dragTarget = getDraggableBody(point);
|
||||
if (dragTarget) {
|
||||
startDrag(dragTarget, point);
|
||||
return;
|
||||
}
|
||||
const body = pickBody(point);
|
||||
if (!body) return;
|
||||
if (!currentScene?.config?.relaxMode) {
|
||||
// Only allow linking same colors unless relax mode explicitly opts out.
|
||||
chain.color = body.plugin.color;
|
||||
} else {
|
||||
chain.color = body.plugin.color;
|
||||
}
|
||||
chain.active = true;
|
||||
chain.color = body.plugin.color;
|
||||
chain.bodies = [body];
|
||||
chain.constraints = [];
|
||||
chain.pointer = point;
|
||||
@@ -589,6 +634,10 @@
|
||||
};
|
||||
|
||||
const handlePointerMove = (evt) => {
|
||||
if (dragConstraint) {
|
||||
updateDrag(getPointerPosition(evt));
|
||||
return;
|
||||
}
|
||||
if (!chain.active) return;
|
||||
if (gameOver || isPaused || levelWon) return;
|
||||
const point = getPointerPosition(evt);
|
||||
@@ -603,7 +652,8 @@
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (body.plugin.color !== chain.color) return;
|
||||
if (!currentScene?.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),
|
||||
@@ -612,7 +662,13 @@
|
||||
addToChain(body);
|
||||
};
|
||||
|
||||
const handlePointerUp = () => finishChain(chain.pointer);
|
||||
const handlePointerUp = () => {
|
||||
if (dragConstraint) {
|
||||
endDrag();
|
||||
return;
|
||||
}
|
||||
finishChain(chain.pointer);
|
||||
};
|
||||
|
||||
render.canvas.addEventListener("mousedown", handlePointerDown);
|
||||
render.canvas.addEventListener("mousemove", handlePointerMove);
|
||||
@@ -706,7 +762,7 @@
|
||||
lineWidth: 2,
|
||||
},
|
||||
};
|
||||
if (currentScene?.config?.blobBalls) {
|
||||
if (currentScene?.config?.blobBalls === "soft") {
|
||||
const cols = 3;
|
||||
const rows = 2;
|
||||
const radius = Math.max(10, config.ballRadius * 0.55);
|
||||
@@ -737,7 +793,24 @@
|
||||
});
|
||||
return { bodies: soft.bodies, constraints: soft.constraints, blobId };
|
||||
}
|
||||
if (currentScene?.config?.blobBalls === "jagged") {
|
||||
const points = [];
|
||||
const segments = 6;
|
||||
for (let i = 0; i < segments; i += 1) {
|
||||
const angle = Math.min((i / segments) * Math.PI * 2, Math.PI * 2);
|
||||
const variance = 0.6 + Math.random() * 0.5;
|
||||
const r = config.ballRadius * variance;
|
||||
points.push({
|
||||
x: x + Math.cos(angle) * r,
|
||||
y: y + Math.sin(angle) * r,
|
||||
});
|
||||
}
|
||||
const body = Bodies.fromVertices(x, y, [points], commonOpts, true);
|
||||
body.plugin = { color, hasEntered: false, entryCheckId: null };
|
||||
return { bodies: [body], constraints: [], blobId: null };
|
||||
}
|
||||
const body = Bodies.circle(x, y, config.ballRadius, commonOpts);
|
||||
body.plugin = { color, hasEntered: false, entryCheckId: null };
|
||||
return { bodies: [body], constraints: [], blobId: null };
|
||||
};
|
||||
|
||||
@@ -823,6 +896,7 @@
|
||||
Body.setVelocity(ball, { x: 0, y: 0 });
|
||||
});
|
||||
resetChainVisuals();
|
||||
endDrag();
|
||||
};
|
||||
|
||||
const handleResize = () => {
|
||||
|
||||
@@ -41,12 +41,11 @@
|
||||
minChain: 3,
|
||||
palette: ["#f472b6", "#38bdf8", "#fbbf24", "#a855f7", "#22c55e"],
|
||||
ballRadius: 26,
|
||||
blobBalls: true,
|
||||
blobBalls: "jagged",
|
||||
winCondition: {
|
||||
type: "score",
|
||||
target: 25000,
|
||||
onWin: { setGravity: -0.55, removeCurves: true },
|
||||
nextSceneId: "scene-grid",
|
||||
},
|
||||
link: {
|
||||
stiffness: 0.7,
|
||||
@@ -55,7 +54,7 @@
|
||||
lineWidth: 3,
|
||||
rope: true,
|
||||
renderType: "line",
|
||||
maxLengthMultiplier: 4.8,
|
||||
maxLengthMultiplier: 5.8,
|
||||
},
|
||||
},
|
||||
createBodies: (w, h) => {
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
minChain: 2,
|
||||
palette: ["#38bdf8", "#f472b6", "#fbbf24", "#22c55e", "#a855f7"],
|
||||
ballRadius: 20,
|
||||
blobBalls: false,
|
||||
blobBalls: "soft",
|
||||
noGameOver: true,
|
||||
relaxMode: true,
|
||||
winCondition: {
|
||||
type: "timer",
|
||||
durationSec: 120,
|
||||
|
||||
Reference in New Issue
Block a user