From 808b2545e25bf3fa8aae42d9a9ceb5087a744be5 Mon Sep 17 00:00:00 2001 From: pobadoba Date: Sun, 10 May 2026 17:26:54 +0900 Subject: [PATCH] update GUI --- index.html | 28 +-- src/babylon_panel.js | 526 ++++++++++++++++++++++++++++++++++++++++++ src/babylon_setup.js | 20 +- src/{ => game}/sfx.js | 0 src/game/state.js | 2 +- src/html_panel.js | 30 +-- src/multi_sketch.js | 3 - 7 files changed, 537 insertions(+), 72 deletions(-) create mode 100644 src/babylon_panel.js rename src/{ => game}/sfx.js (100%) delete mode 100644 src/multi_sketch.js diff --git a/index.html b/index.html index a125440..c31d9a4 100644 --- a/index.html +++ b/index.html @@ -39,28 +39,6 @@ -
-

Settings

-
- -
-
- -
-
- -
-
-

Status

@@ -71,13 +49,15 @@
Time left: 60.0
Key: no
Rounds: 0
-
Adjust settings, then start a run.
- + diff --git a/src/babylon_panel.js b/src/babylon_panel.js new file mode 100644 index 0000000..e983f11 --- /dev/null +++ b/src/babylon_panel.js @@ -0,0 +1,526 @@ +import * as BABYLON from "babylonjs"; +import { sharedState } from "./game/state.js"; +import { seededRng, generateMazeGrid, findDeadEnds } from "./game/maze.js"; +import { gridCellToWorld, isWalkableCell } from "./game/grid.js"; +import { playSfx, primeSfx } from "./game/sfx.js"; +import chestTextureUrl from "../img/img_chest.png"; +import wallTextureUrl from "../img/img_wall.png"; +import groundTextureUrl from "../img/img_ground.png"; +import doorTextureUrl from "../img/img_door.png"; +import gameOverImageUrl from "../img/img_jobapplication.png"; + +// Initialize Babylon.js engine and scene +const canvas = document.getElementById("renderCanvas"); +const engine = new BABYLON.Engine(canvas, true); +const canvasTime = document.getElementById("canvas-time"); +const canvasKey = document.getElementById("canvas-key"); +const canvasRounds = document.getElementById("canvas-rounds"); +const gameOverOverlay = document.getElementById("game-over-overlay"); +const gameOverImage = document.getElementById("game-over-image"); +if (gameOverImage) { + gameOverImage.src = gameOverImageUrl; +} + +const scene = new BABYLON.Scene(engine); +scene.clearColor = new BABYLON.Color4(0.05, 0.07, 0.1, 1); + +const camera = new BABYLON.UniversalCamera("cam", new BABYLON.Vector3(0, 1.6, 0), scene); +camera.minZ = 0.1; +camera.speed = 1.12; +camera.angularSensibility = 1000; +camera.inertia = 0.6; +camera.keysUp = [87]; // W +camera.keysDown = [83]; // S +camera.keysLeft = [65]; // A +camera.keysRight = [68]; // D +camera.checkCollisions = true; +camera.applyGravity = true; +camera.ellipsoid = new BABYLON.Vector3(0.35, 0.9, 0.35); +camera.attachControl(canvas, true); + +const overviewCamera = new BABYLON.ArcRotateCamera( + "overviewCam", + -Math.PI / 2, + Math.PI / 3.2, + 40, + new BABYLON.Vector3(0, 0, 0), + scene, +); +overviewCamera.lowerBetaLimit = 0.2; +overviewCamera.upperBetaLimit = Math.PI / 2.05; +overviewCamera.lowerRadiusLimit = 8; +overviewCamera.inertia = 0.7; + +let cameraMode = "fp"; +scene.activeCamera = camera; +let lastFootstepPosition = null; +let footstepAccumulator = 0; +let footstepElapsed = 0; +let gameOverActive = false; +let lowTimeAlertPlayed = false; + +scene.gravity = new BABYLON.Vector3(0, -0.2, 0); +scene.collisionsEnabled = true; + +canvas.addEventListener("click", () => { + primeSfx(); + if (cameraMode === "fp" && document.pointerLockElement !== canvas) { + canvas.requestPointerLock(); + } +}); + +function updateOverviewCameraForMaze(w, h) { + const mazeSpan = Math.max(w, h) * cellSize; + overviewCamera.radius = Math.max(mazeSpan * 1.05, 16); + overviewCamera.target = new BABYLON.Vector3(0, 0, 0); +} + +function showGameOverScreen() { + gameOverActive = true; + if (gameOverOverlay) { + gameOverOverlay.hidden = false; + } + if (document.pointerLockElement === canvas && document.exitPointerLock) { + document.exitPointerLock(); + } +} + +function hideGameOverScreen() { + gameOverActive = false; + if (gameOverOverlay) { + gameOverOverlay.hidden = true; + } +} + +function restartRunFromGameOver() { + sharedState.runtime.runActive = true; + sharedState.runtime.hasKey = false; + sharedState.runtime.roundsCompleted = 0; + sharedState.runtime.elapsedSeconds = ROUND_TIME_SECONDS; + sharedState.runtime.message = "Run restarted."; + sharedState.config.level = 1; + hideGameOverScreen(); + generateLevel(); +} + +function switchCameraMode() { + if (cameraMode === "fp") { + if (document.pointerLockElement === canvas && document.exitPointerLock) { + document.exitPointerLock(); + } + camera.detachControl(canvas); + overviewCamera.attachControl(canvas, true); + scene.activeCamera = overviewCamera; + cameraMode = "overview"; + sharedState.runtime.message = "Overview camera (press V to return to first-person)."; + return; + } + + overviewCamera.detachControl(canvas); + camera.attachControl(canvas, true); + scene.activeCamera = camera; + cameraMode = "fp"; + sharedState.runtime.message = "First-person camera (W/A/S/D + mouse)."; +} + +window.addEventListener("keydown", (event) => { + if (event.code === "KeyW" || event.code === "KeyA" || event.code === "KeyS" || event.code === "KeyD" || event.code === "KeyV" || event.code === "KeyR") { + primeSfx(); + } + if (event.code === "KeyR" && gameOverActive) { + restartRunFromGameOver(); + return; + } + if (event.code === "KeyV") { + switchCameraMode(); + } +}); + +new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); + +// Central sphere (hidden but kept for reference) +const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2 }, scene); +sphere.isVisible = false; +const sphereMaterial = new BABYLON.StandardMaterial("sphereMaterial", scene); +sphereMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.55, 0.95); +sphereMaterial.emissiveColor = new BABYLON.Color3(0.05, 0.12, 0.2); +sphere.material = sphereMaterial; + +// Main render loop +engine.runRenderLoop(() => { + const level = sharedState.config.level; + sphere.rotation.y += 0.01; + sphere.scaling.x = 1 + (level - 1) * 0.05; + sphere.scaling.z = 1 + (level - 1) * 0.05; + if (canvasTime) { + canvasTime.textContent = `${sharedState.runtime.elapsedSeconds.toFixed(1)}s`; + } + if (canvasKey) { + canvasKey.textContent = sharedState.runtime.hasKey ? "yes" : "no"; + } + if (canvasRounds) { + canvasRounds.textContent = String(sharedState.runtime.roundsCompleted); + } + scene.render(); +}); + +window.addEventListener("resize", () => { + engine.resize(); +}); + +// Maze data structures +let levelMeshes = []; +let chestMap = new Map(); // key: "x,y" -> {mesh, opened} +let keyChestKey = null; +let exitBox = null; +let exitGridPos = null; // track exit grid position for collision checking +let spawnGridPos = null; // track spawn grid position for validation +let spawnMarker = null; +let highlightedChest = null; +const cellSize = 2; +const ROUND_TIME_SECONDS = 60; + +function setChestHighlight(mesh) { + if (highlightedChest === mesh) { + return; + } + + if (highlightedChest) { + highlightedChest.renderOutline = false; + } + + highlightedChest = mesh; + + if (highlightedChest) { + highlightedChest.outlineColor = new BABYLON.Color3(0.85, 0.85, 0.85); + highlightedChest.outlineWidth = 0.08; + highlightedChest.renderOutline = true; + } +} + +function clearLevelMeshes() { + setChestHighlight(null); + for (const m of levelMeshes) { + try { m.dispose(); } catch(e) {} + } + levelMeshes = []; + chestMap.clear(); + keyChestKey = null; + if (exitBox) { try { exitBox.dispose(); } catch(e){}; exitBox = null; } + if (spawnMarker) { try { spawnMarker.dispose(); } catch(e){}; spawnMarker = null; } + exitGridPos = null; + spawnGridPos = null; +} + +function isReservedCell(x, y) { + if (chestMap.has(`${x},${y}`)) return true; + if (exitGridPos && exitGridPos.x === x && exitGridPos.y === y) return true; + return false; +} + +function buildLevelFromGrid(grid) { + clearLevelMeshes(); + const h = grid.length; + const w = grid[0].length; + const halfW = (w * cellSize) / 2; + const halfH = (h * cellSize) / 2; + + const floor = BABYLON.MeshBuilder.CreateGround('levelGround', { width: w*cellSize, height: h*cellSize }, scene); + floor.position = new BABYLON.Vector3(0, 0, 0); + floor.checkCollisions = true; + const fm = new BABYLON.StandardMaterial('floorMat', scene); + fm.specularColor = new BABYLON.Color3(0.1, 0.1, 0.1); + fm.diffuseTexture = new BABYLON.Texture(groundTextureUrl, scene); + fm.diffuseTexture.uScale = Math.max(1, Math.floor(w / 2)); + fm.diffuseTexture.vScale = Math.max(1, Math.floor(h / 2)); + fm.diffuseColor = new BABYLON.Color3(0.9, 0.9, 0.9); + floor.material = fm; + levelMeshes.push(floor); + + const wallMat = new BABYLON.StandardMaterial('wallMat', scene); + wallMat.diffuseTexture = new BABYLON.Texture(wallTextureUrl, scene); + wallMat.diffuseColor = new BABYLON.Color3(0.95, 0.95, 0.95); + + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + if (grid[y][x] === 1) { + const box = BABYLON.MeshBuilder.CreateBox(`wall_${x}_${y}`, { size: cellSize }, scene); + box.position = new BABYLON.Vector3(x*cellSize - halfW + cellSize/2, cellSize/2, y*cellSize - halfH + cellSize/2); + box.material = wallMat; + box.checkCollisions = true; + levelMeshes.push(box); + } + } + } +} + +function placeChestsOnDeadEnds(grid, deadEnds, minCount, seed) { + const rng = seededRng(seed); + for (let i = deadEnds.length - 1; i > 0; i--) { + const j = Math.floor(rng() * (i+1)); + [deadEnds[i], deadEnds[j]] = [deadEnds[j], deadEnds[i]]; + } + const chosen = deadEnds.slice(0, Math.min(minCount, deadEnds.length)); + const halfW = (grid[0].length * cellSize) / 2; + const halfH = (grid.length * cellSize) / 2; + + const chestMat = new BABYLON.StandardMaterial('chestMat', scene); + chestMat.diffuseTexture = new BABYLON.Texture(chestTextureUrl, scene); + chestMat.diffuseColor = new BABYLON.Color3(0.95, 0.95, 0.95); + + for (const [x,y] of chosen) { + const c = BABYLON.MeshBuilder.CreateBox(`chest_${x}_${y}`, { width: cellSize*0.8, height: cellSize*0.6, depth: cellSize*0.6 }, scene); + c.position = new BABYLON.Vector3(x*cellSize - halfW + cellSize/2, cellSize*0.3, y*cellSize - halfH + cellSize/2); + c.material = chestMat; + c.isPickable = true; + levelMeshes.push(c); + chestMap.set(`${x},${y}`, { mesh: c, opened: false }); + } + + if (chosen.length > 0) { + const k = Math.floor(rng() * chosen.length); + const [kx, ky] = chosen[k]; + keyChestKey = `${kx},${ky}`; + const entry = chestMap.get(keyChestKey); + if (entry) { + const km = new BABYLON.StandardMaterial('keyChestMat', scene); + km.diffuseTexture = new BABYLON.Texture(chestTextureUrl, scene); + km.diffuseColor = new BABYLON.Color3(0.95, 0.95, 0.95); + km.emissiveColor = new BABYLON.Color3(0.3, 0.22, 0.02); + entry.mesh.material = km; + } + } +} + +function placeExit(grid, seed) { + const dead = findDeadEnds(grid); + const rng = seededRng(seed+1); + if (dead.length === 0) return; + + // Filter out dead ends that have chests + const availableDead = dead.filter(([x, y]) => !chestMap.has(`${x},${y}`)); + if (availableDead.length === 0) { + // Fallback: use any dead end if no chest-free spot available + // This shouldn't happen in normal cases + const idx = Math.floor(rng() * dead.length); + const [x,y] = dead[idx]; + exitGridPos = { x, y }; + // Continue below + } else { + const idx = Math.floor(rng() * availableDead.length); + const [x,y] = availableDead[idx]; + exitGridPos = { x, y }; + } + + const [x,y] = [exitGridPos.x, exitGridPos.y]; + if (!isWalkableCell(grid, x, y)) { + console.warn("Exit selected on non-walkable cell", { x, y }); + return; + } + const exitWorld = gridCellToWorld(grid, x, y, cellSize); + const ex = exitWorld.x; + const ez = exitWorld.z; + + const plane = BABYLON.MeshBuilder.CreatePlane('exitDoor', { + width: cellSize * 1.35, + height: cellSize * 1.85, + sideOrientation: BABYLON.Mesh.DOUBLESIDE, + }, scene); + const exitMat = new BABYLON.StandardMaterial('exitMat', scene); + exitMat.diffuseTexture = new BABYLON.Texture(doorTextureUrl, scene); + exitMat.diffuseColor = new BABYLON.Color3(0.95, 0.95, 0.95); + exitMat.emissiveColor = new BABYLON.Color3(0.07, 0.07, 0.07); + plane.material = exitMat; + plane.position = new BABYLON.Vector3(ex, cellSize * 0.92, ez); + plane.billboardMode = BABYLON.Mesh.BILLBOARDMODE_Y; + exitBox = plane; + levelMeshes.push(plane); +} + +function spawnCameraAt(grid) { + const h = grid.length; + const w = grid[0].length; + let bestCell = null; + let bestDist = -1; + + // Choose a valid spawn that is far from exit when possible. + for (let y = 1; y < h - 1; y++) { + for (let x = 1; x < w - 1; x++) { + if (!isWalkableCell(grid, x, y)) continue; + if (isReservedCell(x, y)) continue; + + const d = exitGridPos ? Math.hypot(x - exitGridPos.x, y - exitGridPos.y) : 0; + if (d > bestDist) { + bestDist = d; + bestCell = { x, y }; + } + } + } + + if (!bestCell) { + console.warn("No valid spawn cell found."); + return; + } + + spawnGridPos = bestCell; + const spawnWorld = gridCellToWorld(grid, bestCell.x, bestCell.y, cellSize); + const px = spawnWorld.x; + const pz = spawnWorld.z; + + try { + if (camera && camera.position) { + camera.position = new BABYLON.Vector3(px, 1.6, pz); + } + } catch (e) {} + lastFootstepPosition = camera && camera.position ? camera.position.clone() : new BABYLON.Vector3(px, 1.6, pz); + footstepAccumulator = 0; + footstepElapsed = 0; +} + +function generateLevel() { + hideGameOverScreen(); + lowTimeAlertPlayed = false; + if (canvasTime) { + canvasTime.classList.remove("low-time"); + } + const cfg = sharedState.config; + const seed = cfg.seed; + const roundScale = Math.max(0, cfg.level - 1); + const w = Math.max(9, cfg.mazeWidth + roundScale * 2); + const h = Math.max(9, cfg.mazeHeight + roundScale * 2); + const chestCount = Math.max(1, cfg.minChestDeadEnds + roundScale); + const grid = generateMazeGrid(w, h, seed + cfg.level); + updateOverviewCameraForMaze(w, h); + const dead = findDeadEnds(grid); + buildLevelFromGrid(grid); + placeChestsOnDeadEnds(grid, dead, chestCount, seed + cfg.level); + placeExit(grid, seed + cfg.level); + spawnCameraAt(grid); + + const placementValid = + !!exitGridPos && + !!spawnGridPos && + isWalkableCell(grid, exitGridPos.x, exitGridPos.y) && + isWalkableCell(grid, spawnGridPos.x, spawnGridPos.y) && + !(exitGridPos.x === spawnGridPos.x && exitGridPos.y === spawnGridPos.y); + + if (!placementValid) { + sharedState.runtime.message = `Placement warning: spawn/exit invalid on level ${cfg.level}.`; + console.warn("Invalid spawn/exit placement", { exitGridPos, spawnGridPos }); + } else { + sharedState.runtime.message = `Level ${cfg.level} generated (spawn ${spawnGridPos.x},${spawnGridPos.y} / exit ${exitGridPos.x},${exitGridPos.y}).`; + } + lastFootstepPosition = camera && camera.position ? camera.position.clone() : lastFootstepPosition; + footstepAccumulator = 0; + footstepElapsed = 0; + window.requestAnimationFrame(()=>{ /* let scene update */ }); +} + +// Expose API for p5 to call +window.mazeGameApi = { generateLevel }; + +// Pointer interaction for chests +scene.onPointerObservable.add((pi) => { + if (pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) return; + if (!sharedState.runtime.runActive || gameOverActive) return; + const pick = scene.pick(scene.pointerX, scene.pointerY); + if (!pick || !pick.hit || !pick.pickedMesh) return; + const m = pick.pickedMesh; + if (!m.name.startsWith('chest_')) return; + const coords = m.name.split('_').slice(1).join(','); + const entry = chestMap.get(coords); + if (!entry) return; + if (entry.opened) { + primeSfx(); + playSfx("chestClose", 0.8); + playSfx("lose", 0.85); + sharedState.runtime.runActive = false; + sharedState.runtime.message = 'Opened chest again — game over.'; + showGameOverScreen(); + return; + } + primeSfx(); + playSfx("chestOpen", 0.8); + entry.opened = true; + if (coords === keyChestKey) { + sharedState.runtime.hasKey = true; + playSfx("key", 0.85); + sharedState.runtime.message = 'You found the key! Find the exit.'; + } else { + sharedState.runtime.message = 'This chest was empty.'; + } +}); + +// Level transition check +scene.registerBeforeRender(() => { + const targetRay = camera.getForwardRay(cellSize * 3.5); + const targetPick = scene.pickWithRay(targetRay, (mesh) => mesh.name.startsWith('chest_')); + if (targetPick && targetPick.hit && targetPick.pickedMesh) { + setChestHighlight(targetPick.pickedMesh); + } else { + setChestHighlight(null); + } + + if (sharedState.runtime.runActive) { + const dt = engine.getDeltaTime() / 1000; + sharedState.runtime.elapsedSeconds = Math.max(0, sharedState.runtime.elapsedSeconds - dt); + + const isLowTime = sharedState.runtime.elapsedSeconds < 10; + if (isLowTime && !lowTimeAlertPlayed) { + lowTimeAlertPlayed = true; + playSfx("clock", 0.75); + if (canvasTime) { + canvasTime.classList.add("low-time"); + } + } + if (!isLowTime && lowTimeAlertPlayed) { + lowTimeAlertPlayed = false; + if (canvasTime) { + canvasTime.classList.remove("low-time"); + } + } + + if (sharedState.runtime.elapsedSeconds <= 0) { + sharedState.runtime.runActive = false; + sharedState.runtime.message = "Time up — game over."; + playSfx("lose", 0.85); + showGameOverScreen(); + return; + } + } + if (sharedState.runtime.runActive && cameraMode === "fp" && camera && camera.position && document.pointerLockElement === canvas) { + const currentPosition = camera.position; + if (!lastFootstepPosition) { + lastFootstepPosition = currentPosition.clone(); + } + const horizontalDistance = Math.hypot( + currentPosition.x - lastFootstepPosition.x, + currentPosition.z - lastFootstepPosition.z, + ); + footstepAccumulator += horizontalDistance; + footstepElapsed += engine.getDeltaTime(); + if (footstepAccumulator > 0.75 && footstepElapsed > 220) { + playSfx("step", 0.65); + footstepAccumulator = 0; + footstepElapsed = 0; + lastFootstepPosition = currentPosition.clone(); + } + } + if (sharedState.runtime.hasKey && exitBox && camera && camera.position) { + const pos = camera.position; + const ex = exitBox.position.x, ez = exitBox.position.z; + const dist = Math.hypot(pos.x - ex, pos.z - ez); + if (dist < cellSize * 0.9) { + playSfx("win", 0.85); + sharedState.config.level += 1; + sharedState.runtime.hasKey = false; + sharedState.runtime.roundsCompleted += 1; + sharedState.runtime.elapsedSeconds = ROUND_TIME_SECONDS; + sharedState.runtime.message = `Level ${sharedState.config.level} starting.`; + generateLevel(); + } + } +}); + +// Export shared state for p5 to use +export { sharedState }; diff --git a/src/babylon_setup.js b/src/babylon_setup.js index 79f79fd..e983f11 100644 --- a/src/babylon_setup.js +++ b/src/babylon_setup.js @@ -2,7 +2,7 @@ import * as BABYLON from "babylonjs"; import { sharedState } from "./game/state.js"; import { seededRng, generateMazeGrid, findDeadEnds } from "./game/maze.js"; import { gridCellToWorld, isWalkableCell } from "./game/grid.js"; -import { playSfx, primeSfx } from "./sfx.js"; +import { playSfx, primeSfx } from "./game/sfx.js"; import chestTextureUrl from "../img/img_chest.png"; import wallTextureUrl from "../img/img_wall.png"; import groundTextureUrl from "../img/img_ground.png"; @@ -138,8 +138,9 @@ window.addEventListener("keydown", (event) => { new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); -// Placeholder sphere +// Central sphere (hidden but kept for reference) const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2 }, scene); +sphere.isVisible = false; const sphereMaterial = new BABYLON.StandardMaterial("sphereMaterial", scene); sphereMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.55, 0.95); sphereMaterial.emissiveColor = new BABYLON.Color3(0.05, 0.12, 0.2); @@ -151,9 +152,6 @@ engine.runRenderLoop(() => { sphere.rotation.y += 0.01; sphere.scaling.x = 1 + (level - 1) * 0.05; sphere.scaling.z = 1 + (level - 1) * 0.05; - sphereMaterial.diffuseColor = sharedState.runtime.hasKey - ? new BABYLON.Color3(0.25, 0.8, 0.45) - : new BABYLON.Color3(0.2, 0.55, 0.95); if (canvasTime) { canvasTime.textContent = `${sharedState.runtime.elapsedSeconds.toFixed(1)}s`; } @@ -377,18 +375,6 @@ function spawnCameraAt(grid) { lastFootstepPosition = camera && camera.position ? camera.position.clone() : new BABYLON.Vector3(px, 1.6, pz); footstepAccumulator = 0; footstepElapsed = 0; - - if (spawnMarker) { - try { spawnMarker.dispose(); } catch(e) {} - } - const marker = BABYLON.MeshBuilder.CreateSphere('spawnMarker', { diameter: cellSize*0.4 }, scene); - const markerMat = new BABYLON.StandardMaterial('spawnMarkerMat', scene); - markerMat.diffuseColor = new BABYLON.Color3(0.2, 0.6, 0.95); - markerMat.emissiveColor = new BABYLON.Color3(0.1, 0.3, 0.5); - marker.material = markerMat; - marker.position = new BABYLON.Vector3(px, cellSize*0.2, pz); - spawnMarker = marker; - levelMeshes.push(marker); } function generateLevel() { diff --git a/src/sfx.js b/src/game/sfx.js similarity index 100% rename from src/sfx.js rename to src/game/sfx.js diff --git a/src/game/state.js b/src/game/state.js index 0899680..ed015a0 100644 --- a/src/game/state.js +++ b/src/game/state.js @@ -11,6 +11,6 @@ export const sharedState = (window.mazeGameState ??= { hasKey: false, roundsCompleted: 0, elapsedSeconds: 60, - message: "Adjust settings, then start a run.", + message: "Press Start to play.", }, }); diff --git a/src/html_panel.js b/src/html_panel.js index 729ce5e..07e1e39 100644 --- a/src/html_panel.js +++ b/src/html_panel.js @@ -1,5 +1,5 @@ import { sharedState } from "./game/state.js"; -import { playSfx, primeSfx } from "./sfx.js"; +import { playSfx, primeSfx } from "./game/sfx.js"; // Handler functions (same as p5_panel but without p5 scoping) function resetRun(message) { @@ -29,9 +29,8 @@ function randomizeSeed() { // Update display from shared state function updateDisplay() { - document.getElementById("value-width").textContent = sharedState.config.mazeWidth; - document.getElementById("value-height").textContent = sharedState.config.mazeHeight; - document.getElementById("value-deadends").textContent = sharedState.config.minChestDeadEnds; + document.getElementById("status-seed").textContent = sharedState.config.seed; + document.getElementById("status-level").textContent = sharedState.config.level; // Calculate effective maze size and chest count based on current level const roundScale = Math.max(0, sharedState.config.level - 1); @@ -39,8 +38,6 @@ function updateDisplay() { const effectiveHeight = Math.max(9, sharedState.config.mazeHeight + roundScale * 2); const effectiveChests = Math.max(1, sharedState.config.minChestDeadEnds + roundScale); - document.getElementById("status-seed").textContent = sharedState.config.seed; - document.getElementById("status-level").textContent = sharedState.config.level; document.getElementById("status-maze-size").textContent = `${effectiveWidth}x${effectiveHeight}`; document.getElementById("status-chests").textContent = effectiveChests; document.getElementById("status-time").textContent = sharedState.runtime.elapsedSeconds.toFixed(1); @@ -68,27 +65,6 @@ document.getElementById("btn-randomize").addEventListener("click", () => { randomizeSeed(); }); -document.getElementById("slider-width").addEventListener("input", (e) => { - primeSfx(); - const value = parseInt(e.target.value) | 1; - sharedState.config.mazeWidth = value; - document.getElementById("value-width").textContent = value; -}); - -document.getElementById("slider-height").addEventListener("input", (e) => { - primeSfx(); - const value = parseInt(e.target.value) | 1; - sharedState.config.mazeHeight = value; - document.getElementById("value-height").textContent = value; -}); - -document.getElementById("slider-deadends").addEventListener("input", (e) => { - primeSfx(); - const value = parseInt(e.target.value); - sharedState.config.minChestDeadEnds = value; - document.getElementById("value-deadends").textContent = value; -}); - // Update status display on game loop setInterval(() => { if (sharedState.runtime.runActive) { diff --git a/src/multi_sketch.js b/src/multi_sketch.js deleted file mode 100644 index f9e1abb..0000000 --- a/src/multi_sketch.js +++ /dev/null @@ -1,3 +0,0 @@ -// Import Babylon.js game logic and HTML control panel -import "./babylon_setup.js"; -import "./html_panel.js";