157 lines
4.7 KiB
JavaScript
157 lines
4.7 KiB
JavaScript
(() => {
|
|
const create = () => {
|
|
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 handlers = {
|
|
onPauseToggle: null,
|
|
onRestart: null,
|
|
onSceneChange: null,
|
|
};
|
|
|
|
if (pauseBtn) {
|
|
pauseBtn.addEventListener("click", () => {
|
|
if (handlers.onPauseToggle) handlers.onPauseToggle();
|
|
});
|
|
}
|
|
|
|
if (restartBtn) {
|
|
restartBtn.addEventListener("click", () => {
|
|
if (handlers.onRestart) handlers.onRestart();
|
|
});
|
|
}
|
|
|
|
if (sceneSelectEl) {
|
|
sceneSelectEl.addEventListener("change", (e) => {
|
|
if (handlers.onSceneChange) handlers.onSceneChange(e.target.value);
|
|
});
|
|
}
|
|
|
|
window.addEventListener("keydown", (e) => {
|
|
if (e.key === "Escape" && handlers.onPauseToggle) {
|
|
handlers.onPauseToggle();
|
|
}
|
|
});
|
|
|
|
const setHandlers = (nextHandlers = {}) => {
|
|
Object.assign(handlers, nextHandlers);
|
|
};
|
|
|
|
const setSceneOptions = (scenes, activeId) => {
|
|
if (!sceneSelectEl) return;
|
|
sceneSelectEl.innerHTML = "";
|
|
scenes.forEach((scene) => {
|
|
const opt = document.createElement("option");
|
|
opt.value = scene.id;
|
|
opt.textContent = scene.name;
|
|
sceneSelectEl.appendChild(opt);
|
|
});
|
|
if (activeId) {
|
|
sceneSelectEl.value = activeId;
|
|
}
|
|
};
|
|
|
|
const setSceneSelection = (sceneId) => {
|
|
if (sceneSelectEl) {
|
|
sceneSelectEl.value = sceneId;
|
|
}
|
|
};
|
|
|
|
const setPauseState = (paused) => {
|
|
if (pauseOverlay) {
|
|
pauseOverlay.classList.toggle("visible", paused);
|
|
}
|
|
if (pauseBtn) {
|
|
pauseBtn.textContent = paused ? "Resume" : "Pause";
|
|
}
|
|
};
|
|
|
|
const showGameOver = (score) => {
|
|
if (finalScoreEl) finalScoreEl.textContent = score;
|
|
if (gameOverEl) gameOverEl.classList.add("visible");
|
|
};
|
|
|
|
const hideGameOver = () => {
|
|
if (gameOverEl) gameOverEl.classList.remove("visible");
|
|
};
|
|
|
|
const spawnScorePopup = (point, amount, color) => {
|
|
if (!point || !sceneEl) 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 updateHud = ({
|
|
spawnIntervalMs,
|
|
minChain,
|
|
chainLength,
|
|
score,
|
|
highScore,
|
|
activeColor,
|
|
}) => {
|
|
if (spawnRateEl) spawnRateEl.textContent = `${spawnIntervalMs} ms`;
|
|
if (minLinkEl) minLinkEl.textContent = minChain;
|
|
if (chainLenEl) chainLenEl.textContent = chainLength;
|
|
if (scoreEl) scoreEl.textContent = score;
|
|
if (highScoreEl) highScoreEl.textContent = highScore;
|
|
if (activeColorEl) {
|
|
if (activeColor) {
|
|
activeColorEl.textContent = "";
|
|
activeColorEl.style.display = "inline-block";
|
|
activeColorEl.style.width = "14px";
|
|
activeColorEl.style.height = "14px";
|
|
activeColorEl.style.borderRadius = "50%";
|
|
activeColorEl.style.background = activeColor;
|
|
activeColorEl.style.border = "1px solid rgba(255,255,255,0.3)";
|
|
} else {
|
|
activeColorEl.removeAttribute("style");
|
|
activeColorEl.textContent = "—";
|
|
}
|
|
}
|
|
};
|
|
|
|
const buildLegend = (palette) => {
|
|
if (!paletteLegendEl) return;
|
|
paletteLegendEl.innerHTML = "";
|
|
palette.forEach((color) => {
|
|
const swatch = document.createElement("span");
|
|
swatch.style.background = color;
|
|
paletteLegendEl.appendChild(swatch);
|
|
});
|
|
};
|
|
|
|
return {
|
|
sceneEl,
|
|
updateHud,
|
|
buildLegend,
|
|
spawnScorePopup,
|
|
setPauseState,
|
|
showGameOver,
|
|
hideGameOver,
|
|
setSceneOptions,
|
|
setSceneSelection,
|
|
setHandlers,
|
|
};
|
|
};
|
|
|
|
window.PhysilinksUI = { create };
|
|
})();
|