add back game over from chest

This commit is contained in:
pobadoba
2026-05-10 17:01:02 +09:00
parent 7e2d6243b2
commit 9b68630764
6 changed files with 103 additions and 30 deletions

View File

@@ -6,6 +6,8 @@ import { playSfx, primeSfx } from "./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");
@@ -13,6 +15,11 @@ 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);
@@ -49,6 +56,7 @@ scene.activeCamera = camera;
let lastFootstepPosition = null;
let footstepAccumulator = 0;
let footstepElapsed = 0;
let gameOverActive = false;
scene.gravity = new BABYLON.Vector3(0, -0.2, 0);
scene.collisionsEnabled = true;
@@ -66,6 +74,34 @@ function updateOverviewCameraForMaze(w, h) {
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 = 0;
sharedState.runtime.message = "Run restarted.";
sharedState.config.level = 1;
hideGameOverScreen();
generateLevel();
}
function switchCameraMode() {
if (cameraMode === "fp") {
if (document.pointerLockElement === canvas && document.exitPointerLock) {
@@ -87,9 +123,13 @@ function switchCameraMode() {
}
window.addEventListener("keydown", (event) => {
if (event.code === "KeyW" || event.code === "KeyA" || event.code === "KeyS" || event.code === "KeyD" || event.code === "KeyV") {
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();
}
@@ -280,39 +320,21 @@ function placeExit(grid, seed) {
const exitWorld = gridCellToWorld(grid, x, y, cellSize);
const ex = exitWorld.x;
const ez = exitWorld.z;
const worldSpan = Math.max(grid[0].length, grid.length) * cellSize;
// Ground plane indicator (larger + slightly raised to avoid z-fighting)
const plane = BABYLON.MeshBuilder.CreateGround('exitZone', { width: cellSize*1.4, height: cellSize*1.4 }, scene);
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.diffuseColor = new BABYLON.Color3(0.25, 0.2, 0.03);
exitMat.emissiveColor = new BABYLON.Color3(1.0, 0.85, 0.15);
exitMat.disableLighting = true;
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, 0.08, ez);
plane.position = new BABYLON.Vector3(ex, cellSize * 0.92, ez);
plane.billboardMode = BABYLON.Mesh.BILLBOARDMODE_Y;
exitBox = plane;
levelMeshes.push(plane);
// Very tall beacon for visibility over maze walls
const beaconHeight = Math.max(18, worldSpan * 0.8);
const pillar = BABYLON.MeshBuilder.CreateCylinder('exitPillar', { diameter: cellSize*0.55, height: beaconHeight }, scene);
const pillarMat = new BABYLON.StandardMaterial('exitPillarMat', scene);
pillarMat.diffuseColor = new BABYLON.Color3(0.95, 0.8, 0.1);
pillarMat.emissiveColor = new BABYLON.Color3(1.0, 0.7, 0.1);
pillarMat.disableLighting = true;
pillar.material = pillarMat;
pillar.position = new BABYLON.Vector3(ex, beaconHeight * 0.5, ez);
levelMeshes.push(pillar);
// Bright orb at the top of beacon
const orb = BABYLON.MeshBuilder.CreateSphere('exitOrb', { diameter: cellSize * 1.0 }, scene);
const orbMat = new BABYLON.StandardMaterial('exitOrbMat', scene);
orbMat.diffuseColor = new BABYLON.Color3(1.0, 0.9, 0.3);
orbMat.emissiveColor = new BABYLON.Color3(1.0, 0.9, 0.35);
orbMat.disableLighting = true;
orb.material = orbMat;
orb.position = new BABYLON.Vector3(ex, beaconHeight + cellSize * 0.7, ez);
levelMeshes.push(orb);
}
function spawnCameraAt(grid) {
@@ -368,6 +390,7 @@ function spawnCameraAt(grid) {
}
function generateLevel() {
hideGameOverScreen();
const cfg = sharedState.config;
const seed = cfg.seed;
const w = Math.max(9, cfg.mazeWidth);
@@ -415,8 +438,10 @@ scene.onPointerObservable.add((pi) => {
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();

View File

@@ -3,6 +3,7 @@ const soundFiles = {
chestOpen: "/sfx/sfx_chest_open.wav",
click: "/sfx/sfx_click.wav",
key: "/sfx/sfx_key.wav",
lose: "/sfx/sfx_lose.wav",
step: "/sfx/sfx_step.wav",
win: "/sfx/sfx_win.wav",
};