Extract UI handling to dedicated module
This commit is contained in:
107
main.js
107
main.js
@@ -31,20 +31,8 @@
|
||||
},
|
||||
};
|
||||
|
||||
const sceneEl = document.getElementById("scene-wrapper");
|
||||
const activeColorEl = document.getElementById("active-color");
|
||||
const chainLenEl = document.getElementById("chain-length");
|
||||
const spawnRateEl = document.getElementById("spawn-rate");
|
||||
const minLinkEl = document.getElementById("min-link");
|
||||
const paletteLegendEl = document.getElementById("palette-legend");
|
||||
const scoreEl = document.getElementById("score");
|
||||
const highScoreEl = document.getElementById("high-score");
|
||||
const sceneSelectEl = document.getElementById("scene-select");
|
||||
const gameOverEl = document.getElementById("game-over");
|
||||
const finalScoreEl = document.getElementById("final-score");
|
||||
const restartBtn = document.getElementById("restart-btn");
|
||||
const pauseBtn = document.getElementById("pause-btn");
|
||||
const pauseOverlay = document.getElementById("pause-overlay");
|
||||
const ui = window.PhysilinksUI.create();
|
||||
const { sceneEl } = ui;
|
||||
|
||||
let width = sceneEl.clientWidth;
|
||||
let height = sceneEl.clientHeight;
|
||||
@@ -130,21 +118,10 @@
|
||||
}
|
||||
};
|
||||
|
||||
const populateSceneSelect = () => {
|
||||
if (!sceneSelectEl) return;
|
||||
sceneSelectEl.innerHTML = "";
|
||||
scenes.forEach((scene) => {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = scene.id;
|
||||
opt.textContent = scene.name;
|
||||
sceneSelectEl.appendChild(opt);
|
||||
});
|
||||
};
|
||||
|
||||
const applyScene = (sceneId) => {
|
||||
const next = scenes.find((s) => s.id === sceneId) || scenes[0];
|
||||
currentScene = next;
|
||||
if (sceneSelectEl) sceneSelectEl.value = next.id;
|
||||
ui.setSceneSelection(next.id);
|
||||
Object.assign(config, next.config);
|
||||
config.link = { ...next.config.link };
|
||||
engine.gravity.y = config.gravity;
|
||||
@@ -230,10 +207,8 @@
|
||||
stopSpawner();
|
||||
stopRunner();
|
||||
engine.timing.timeScale = 0;
|
||||
pauseOverlay.classList.remove("visible");
|
||||
pauseBtn.textContent = "Pause";
|
||||
finalScoreEl.textContent = score;
|
||||
gameOverEl.classList.add("visible");
|
||||
ui.setPauseState(false);
|
||||
ui.showGameOver(score);
|
||||
};
|
||||
|
||||
const restartGame = () => {
|
||||
@@ -246,9 +221,8 @@
|
||||
World.remove(world, ball);
|
||||
});
|
||||
balls.length = 0;
|
||||
gameOverEl.classList.remove("visible");
|
||||
pauseOverlay.classList.remove("visible");
|
||||
pauseBtn.textContent = "Pause";
|
||||
ui.hideGameOver();
|
||||
ui.setPauseState(false);
|
||||
engine.timing.timeScale = 1;
|
||||
startRunner();
|
||||
updateHud();
|
||||
@@ -264,8 +238,7 @@
|
||||
if (gameOver) return;
|
||||
if (state === isPaused) return;
|
||||
isPaused = state;
|
||||
pauseBtn.textContent = isPaused ? "Resume" : "Pause";
|
||||
pauseOverlay.classList.toggle("visible", isPaused);
|
||||
ui.setPauseState(isPaused);
|
||||
if (isPaused) {
|
||||
resetChainVisuals();
|
||||
stopSpawner();
|
||||
@@ -328,18 +301,6 @@
|
||||
updateHud();
|
||||
};
|
||||
|
||||
const spawnScorePopup = (point, amount, color) => {
|
||||
if (!point) return;
|
||||
const el = document.createElement("div");
|
||||
el.className = "floating-score";
|
||||
el.textContent = `+${amount}`;
|
||||
el.style.left = `${point.x}px`;
|
||||
el.style.top = `${point.y}px`;
|
||||
el.style.color = color || "#e0f2fe";
|
||||
sceneEl.appendChild(el);
|
||||
setTimeout(() => el.remove(), 950);
|
||||
};
|
||||
|
||||
const finishChain = (releasePoint) => {
|
||||
if (!chain.active || gameOver || isPaused) return;
|
||||
if (chain.bodies.length >= config.minChain) {
|
||||
@@ -349,7 +310,7 @@
|
||||
highScore = score;
|
||||
saveHighScore();
|
||||
}
|
||||
spawnScorePopup(releasePoint || chain.pointer, gain, chain.color);
|
||||
ui.spawnScorePopup(releasePoint || chain.pointer, gain, chain.color);
|
||||
chain.constraints.forEach((c) => World.remove(world, c));
|
||||
chain.bodies.forEach((body) => {
|
||||
cleanupBall(body);
|
||||
@@ -457,32 +418,18 @@
|
||||
);
|
||||
|
||||
const updateHud = () => {
|
||||
spawnRateEl.textContent = `${config.spawnIntervalMs} ms`;
|
||||
minLinkEl.textContent = config.minChain;
|
||||
chainLenEl.textContent = chain.bodies.length;
|
||||
scoreEl.textContent = score;
|
||||
highScoreEl.textContent = highScore;
|
||||
if (chain.color) {
|
||||
activeColorEl.textContent = "";
|
||||
activeColorEl.style.display = "inline-block";
|
||||
activeColorEl.style.width = "14px";
|
||||
activeColorEl.style.height = "14px";
|
||||
activeColorEl.style.borderRadius = "50%";
|
||||
activeColorEl.style.background = chain.color;
|
||||
activeColorEl.style.border = "1px solid rgba(255,255,255,0.3)";
|
||||
} else {
|
||||
activeColorEl.removeAttribute("style");
|
||||
activeColorEl.textContent = "—";
|
||||
}
|
||||
ui.updateHud({
|
||||
spawnIntervalMs: config.spawnIntervalMs,
|
||||
minChain: config.minChain,
|
||||
chainLength: chain.bodies.length,
|
||||
score,
|
||||
highScore,
|
||||
activeColor: chain.color,
|
||||
});
|
||||
};
|
||||
|
||||
const buildLegend = () => {
|
||||
paletteLegendEl.innerHTML = "";
|
||||
config.palette.forEach((color) => {
|
||||
const swatch = document.createElement("span");
|
||||
swatch.style.background = color;
|
||||
paletteLegendEl.appendChild(swatch);
|
||||
});
|
||||
ui.buildLegend(config.palette);
|
||||
};
|
||||
|
||||
const handleResize = () => {
|
||||
@@ -581,16 +528,14 @@
|
||||
});
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
restartBtn.addEventListener("click", restartGame);
|
||||
pauseBtn.addEventListener("click", () => setPaused(!isPaused));
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
setPaused(!isPaused);
|
||||
}
|
||||
ui.setHandlers({
|
||||
onPauseToggle: () => setPaused(!isPaused),
|
||||
onRestart: restartGame,
|
||||
onSceneChange: (id) => applyScene(id),
|
||||
});
|
||||
if (sceneSelectEl) {
|
||||
sceneSelectEl.addEventListener("change", (e) => applyScene(e.target.value));
|
||||
}
|
||||
populateSceneSelect();
|
||||
ui.setSceneOptions(
|
||||
scenes,
|
||||
(currentScene && currentScene.id) || defaultSceneId,
|
||||
);
|
||||
applyScene((currentScene && currentScene.id) || defaultSceneId);
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user