Improve color goal display with swatches

This commit is contained in:
Daddy32
2025-12-13 20:20:08 +01:00
parent 854f19503a
commit 37607ef148
2 changed files with 87 additions and 12 deletions

75
main.js
View File

@@ -96,10 +96,12 @@
};
const balls = [];
const blobConstraints = new Map();
let spawnTimer = null;
let score = 0;
let highScore = 0;
let clearedCount = 0;
let clearedByColor = {};
let gameOver = false;
let isPaused = false;
let levelWon = false;
@@ -135,6 +137,7 @@
engine.gravity.y = config.gravity;
clearedCount = 0;
levelWon = false;
clearedByColor = {};
highScore = loadHighScore(next.id);
rebuildSceneBodies();
buildLegend();
@@ -309,6 +312,7 @@
levelWon = false;
score = 0;
clearedCount = 0;
clearedByColor = {};
resetChainVisuals();
balls.forEach((ball) => {
cleanupBall(ball);
@@ -379,6 +383,17 @@
Body.applyForce(ball, ball.position, force);
});
}
if (winCond.onWin.swirlBalls) {
balls.forEach((ball) => {
const angle = Math.random() * Math.PI * 2;
const mag = 0.06;
Body.applyForce(ball, ball.position, {
x: Math.cos(angle) * mag,
y: -Math.abs(Math.sin(angle)) * mag * 1.5,
});
Body.setAngularVelocity(ball, (Math.random() - 0.5) * 0.3);
});
}
if (winCond.onWin.removeCurves) {
const remaining = [];
boundaries.forEach((b) => {
@@ -457,13 +472,36 @@
}
ui.spawnScorePopup(releasePoint || chain.pointer, gain, chain.color);
chain.constraints.forEach((c) => World.remove(world, c));
const blobIds = new Set();
chain.bodies.forEach((body) => {
cleanupBall(body);
World.remove(world, body);
if (body.plugin?.blobId) {
blobIds.add(body.plugin.blobId);
} else {
if (body.plugin?.color) {
const key = normalizeColor(body.plugin.color);
clearedByColor[key] = (clearedByColor[key] || 0) + 1;
}
cleanupBall(body);
World.remove(world, body);
}
});
blobIds.forEach((id) => {
balls
.filter((b) => b.plugin?.blobId === id)
.forEach((b) => {
if (b.plugin?.color) {
const key = normalizeColor(b.plugin.color);
clearedByColor[key] = (clearedByColor[key] || 0) + 1;
}
});
removeBlob(id);
});
// Remove cleared balls from tracking list.
for (let i = balls.length - 1; i >= 0; i -= 1) {
if (chain.bodies.includes(balls[i])) {
if (
chain.bodies.includes(balls[i]) ||
(balls[i].plugin?.blobId && blobIds.has(balls[i].plugin?.blobId))
) {
balls.splice(i, 1);
}
}
@@ -644,6 +682,8 @@
return Bodies.circle(x, y, config.ballRadius, commonOpts);
};
const normalizeColor = (c) => (c || "").trim().toLowerCase();
const getGoalState = () => {
const winCond = currentScene?.config?.winCondition;
if (!winCond) return null;
@@ -666,14 +706,29 @@
};
}
if (winCond.type === "colorClear" && Array.isArray(winCond.targets)) {
const target = winCond.targets.reduce(
(sum, t) => sum + (t.count || 0),
0,
);
const targets = winCond.targets.map((t) => ({
color: normalizeColor(t.color),
count: t.count || 0,
}));
const totalTarget = targets.reduce((sum, t) => sum + t.count, 0);
let totalAchieved = 0;
const parts = targets.map((t) => {
const got = Math.min(
t.count,
clearedByColor[normalizeColor(t.color)] || 0,
);
totalAchieved += got;
const remaining = Math.max(0, t.count - got);
return `${got}/${t.count} (${remaining} left)`;
});
return {
label: "Clear target colors",
progress: target > 0 ? (100 * clearedCount) / target : 0,
met: false,
label: parts.join(" • "),
progress: totalTarget > 0 ? (100 * totalAchieved) / totalTarget : 0,
met: targets.every(
(t) =>
(clearedByColor[normalizeColor(t.color)] || 0) >= (t.count || 0),
),
colors: targets.map((t) => t.color),
};
}
return null;