diff --git a/src/babylon_setup.js b/src/babylon_setup.js index 2aa1797..a7e43e0 100644 --- a/src/babylon_setup.js +++ b/src/babylon_setup.js @@ -38,15 +38,63 @@ 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; + scene.gravity = new BABYLON.Vector3(0, -0.2, 0); scene.collisionsEnabled = true; canvas.addEventListener("click", () => { - if (document.pointerLockElement !== canvas) { + 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 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 === "KeyV") { + switchCameraMode(); + } +}); + new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); // Placeholder sphere @@ -320,6 +368,7 @@ function generateLevel() { const w = Math.max(9, cfg.mazeWidth); const h = Math.max(9, cfg.mazeHeight); const grid = generateMazeGrid(w, h, seed + cfg.level); + updateOverviewCameraForMaze(w, h); const dead = findDeadEnds(grid); buildLevelFromGrid(grid); placeChestsOnDeadEnds(grid, dead, cfg.minChestDeadEnds, seed + cfg.level);