feat: game over screen
This commit is contained in:
@@ -136,6 +136,64 @@ canvas {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.p5-particles-container {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.p5-game-over-panel {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
background: rgba(0, 0, 0, 0.95);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.p5-game-over-panel[hidden] {
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.p5-sketch-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.game-over-info {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.game-over-info .game-over-text {
|
||||
margin-top: 0;
|
||||
font-size: clamp(24px, 4vw, 40px);
|
||||
font-weight: 700;
|
||||
color: #f3f7ff;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.game-over-info .game-over-subtext {
|
||||
font-size: 14px;
|
||||
color: #c9d8ea;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.game-over-image {
|
||||
width: min(70%, 460px);
|
||||
max-height: 52vh;
|
||||
|
||||
14
index.html
14
index.html
@@ -19,11 +19,15 @@
|
||||
<div class="canvas-hud-row"><span>Has key</span><strong id="canvas-key">no</strong></div>
|
||||
<div class="canvas-hud-row"><span>Rounds</span><strong id="canvas-rounds">0</strong></div>
|
||||
</div>
|
||||
<div id="game-over-overlay" class="game-over-overlay" hidden>
|
||||
<img id="game-over-image" alt="Game over" class="game-over-image" />
|
||||
<div class="game-over-text">Game Over</div>
|
||||
<div class="game-over-subtext">Press R to play again</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="p5-game-over-panel" class="panel p5-game-over-panel" hidden>
|
||||
<div class="panel-label">GAME OVER</div>
|
||||
<div id="p5-sketch-container" class="p5-sketch-container"></div>
|
||||
<div class="game-over-info">
|
||||
<div class="game-over-text">Game Over</div>
|
||||
<div class="game-over-subtext">Press R to play again</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
335
package-lock.json
generated
335
package-lock.json
generated
@@ -1,20 +1,36 @@
|
||||
{
|
||||
"name": "p5js-vite",
|
||||
"name": "untitled-maze-game",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "p5js-vite",
|
||||
"name": "untitled-maze-game",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"babylonjs": "^9.5.1",
|
||||
"p5": "^2.2.3",
|
||||
"p5js-wrapper": "^1.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^8.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@davepagurek/bezier-path": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@davepagurek/bezier-path/-/bezier-path-0.0.7.tgz",
|
||||
"integrity": "sha512-CVlnCOrV1iy4Z12T756i9l4G6kF7r8uhlnb+xqDemAMmWQB+8Q0b+8VEqIiUfywgZDSiDr18Rm7pZlnA69rE8Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
@@ -49,6 +65,12 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@japont/unicode-range": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@japont/unicode-range/-/unicode-range-1.0.0.tgz",
|
||||
"integrity": "sha512-BckHvA2XdjRBVAWe2uceNuRf78lBeI28kyWEbfr/Q2pE17POkwuZ6WWY/UMv8FL9iBxhW4xfDoNLM9UVZaTeUQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
||||
@@ -371,6 +393,30 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.3.5",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
|
||||
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babylonjs": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-9.5.1.tgz",
|
||||
@@ -378,6 +424,16 @@
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/colorjs.io": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.6.1.tgz",
|
||||
"integrity": "sha512-8lyR2wHzuIykCpqHKgluGsqQi5iDm3/a2IgP2GBZrasn2sBRkE4NOGsglZxWLs/jZQoNkmA/KM/8NV16rLUdBg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/color"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
@@ -388,6 +444,58 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
|
||||
"integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^5.2.0",
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"escodegen": "bin/escodegen.js",
|
||||
"esgenerate": "bin/esgenerate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/estraverse": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
@@ -421,6 +529,36 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gifenc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/gifenc/-/gifenc-1.0.3.tgz",
|
||||
"integrity": "sha512-xdr6AdrfGBcfzncONUOlXMBuc5wJDtOueE3c5rdG0oNgtINLD+f2iFZltrBRZYzACRbKr+mSVU/x98zv2u3jmw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "19.9.2",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.9.2.tgz",
|
||||
"integrity": "sha512-0i6cuo6ER6usEOtKajUUDj92zlG+KArFia0857xxiEHAQcUwh/RtOQocui1LPJwunSYT574Pk64aNva1kwtxZg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-browser-languagedetector": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-4.3.1.tgz",
|
||||
"integrity": "sha512-KIToAzf8zwWvacgnRwJp63ase26o24AuNUlfNVJ5YZAFmdGhsJpmFClxXPuk9rv1FMI4lnc8zLSqgZPEZMrW4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/libtess": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/libtess/-/libtess-1.2.2.tgz",
|
||||
"integrity": "sha512-Nps8HPeVVcsmJxUvFLKVJcCgcz+1ajPTXDVAVPs6+giOQP4AHV31uZFFkh+CKow/bkB7GbZWKmwmit7myaqDSw==",
|
||||
"license": "SGI-B-2.0"
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
@@ -713,10 +851,32 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/omggif": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
|
||||
"integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/p5": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/p5/-/p5-1.4.1.tgz",
|
||||
"integrity": "sha512-3/X+qb0bK2Cg8nuZNpZZvzxkeUSRghOf0S+l8c+U8yIkUTVSbbcV0R8y96rx3InVBVhk8cH9kFC93VlZZElqSw=="
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/p5/-/p5-2.2.3.tgz",
|
||||
"integrity": "sha512-jz9uy0k3Fcj9vKSOafQlIrpaPZZjO4rAEBZF6dGkbokisshP0M3aFm4qtLHYCoEW1XJSkFaVaOMILCQAQxUHHA==",
|
||||
"license": "LGPL-2.1",
|
||||
"dependencies": {
|
||||
"@davepagurek/bezier-path": "^0.0.7",
|
||||
"@japont/unicode-range": "^1.0.0",
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-walk": "^8.3.4",
|
||||
"colorjs.io": "^0.6.0",
|
||||
"escodegen": "^2.1.0",
|
||||
"gifenc": "^1.0.3",
|
||||
"i18next": "^19.0.2",
|
||||
"i18next-browser-languagedetector": "^4.0.1",
|
||||
"libtess": "^1.2.2",
|
||||
"omggif": "^1.0.10",
|
||||
"pako": "^2.1.0",
|
||||
"zod": "^4.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/p5js-wrapper": {
|
||||
"version": "1.2.3",
|
||||
@@ -726,6 +886,18 @@
|
||||
"p5": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/p5js-wrapper/node_modules/p5": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/p5/-/p5-1.11.13.tgz",
|
||||
"integrity": "sha512-gfGo4AkyuNMs6Ko7UNFM9K2edqFRGyLrFaYUB+XXF127JVdEPu0BIaC5uDDNJpsRMOD9hJMUpsOH4HkfuNhvhA==",
|
||||
"license": "LGPL-2.1"
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -809,6 +981,16 @@
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
@@ -921,9 +1103,28 @@
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="
|
||||
},
|
||||
"@davepagurek/bezier-path": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@davepagurek/bezier-path/-/bezier-path-0.0.7.tgz",
|
||||
"integrity": "sha512-CVlnCOrV1iy4Z12T756i9l4G6kF7r8uhlnb+xqDemAMmWQB+8Q0b+8VEqIiUfywgZDSiDr18Rm7pZlnA69rE8Q=="
|
||||
},
|
||||
"@emnapi/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
@@ -955,6 +1156,11 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"@japont/unicode-range": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@japont/unicode-range/-/unicode-range-1.0.0.tgz",
|
||||
"integrity": "sha512-BckHvA2XdjRBVAWe2uceNuRf78lBeI28kyWEbfr/Q2pE17POkwuZ6WWY/UMv8FL9iBxhW4xfDoNLM9UVZaTeUQ=="
|
||||
},
|
||||
"@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
||||
@@ -1097,17 +1303,61 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="
|
||||
},
|
||||
"acorn-walk": {
|
||||
"version": "8.3.5",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
|
||||
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
|
||||
"requires": {
|
||||
"acorn": "^8.11.0"
|
||||
}
|
||||
},
|
||||
"babylonjs": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-9.5.1.tgz",
|
||||
"integrity": "sha512-EXROfSz1k+Mg88Qh/SrElEz1zp5QVFG4H+2OyCZ+uEXe4fFeY667N9kjMx2+6Y2XFCxKxf4q+za6k+B1x1qbGg=="
|
||||
},
|
||||
"colorjs.io": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.6.1.tgz",
|
||||
"integrity": "sha512-8lyR2wHzuIykCpqHKgluGsqQi5iDm3/a2IgP2GBZrasn2sBRkE4NOGsglZxWLs/jZQoNkmA/KM/8NV16rLUdBg=="
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"dev": true
|
||||
},
|
||||
"escodegen": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
|
||||
"integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
|
||||
"requires": {
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^5.2.0",
|
||||
"esutils": "^2.0.2",
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
|
||||
},
|
||||
"fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
@@ -1122,6 +1372,32 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"gifenc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/gifenc/-/gifenc-1.0.3.tgz",
|
||||
"integrity": "sha512-xdr6AdrfGBcfzncONUOlXMBuc5wJDtOueE3c5rdG0oNgtINLD+f2iFZltrBRZYzACRbKr+mSVU/x98zv2u3jmw=="
|
||||
},
|
||||
"i18next": {
|
||||
"version": "19.9.2",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.9.2.tgz",
|
||||
"integrity": "sha512-0i6cuo6ER6usEOtKajUUDj92zlG+KArFia0857xxiEHAQcUwh/RtOQocui1LPJwunSYT574Pk64aNva1kwtxZg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.0"
|
||||
}
|
||||
},
|
||||
"i18next-browser-languagedetector": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-4.3.1.tgz",
|
||||
"integrity": "sha512-KIToAzf8zwWvacgnRwJp63ase26o24AuNUlfNVJ5YZAFmdGhsJpmFClxXPuk9rv1FMI4lnc8zLSqgZPEZMrW4g==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.5.5"
|
||||
}
|
||||
},
|
||||
"libtess": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/libtess/-/libtess-1.2.2.tgz",
|
||||
"integrity": "sha512-Nps8HPeVVcsmJxUvFLKVJcCgcz+1ajPTXDVAVPs6+giOQP4AHV31uZFFkh+CKow/bkB7GbZWKmwmit7myaqDSw=="
|
||||
},
|
||||
"lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
@@ -1225,10 +1501,30 @@
|
||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||
"dev": true
|
||||
},
|
||||
"omggif": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
|
||||
"integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="
|
||||
},
|
||||
"p5": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/p5/-/p5-1.4.1.tgz",
|
||||
"integrity": "sha512-3/X+qb0bK2Cg8nuZNpZZvzxkeUSRghOf0S+l8c+U8yIkUTVSbbcV0R8y96rx3InVBVhk8cH9kFC93VlZZElqSw=="
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/p5/-/p5-2.2.3.tgz",
|
||||
"integrity": "sha512-jz9uy0k3Fcj9vKSOafQlIrpaPZZjO4rAEBZF6dGkbokisshP0M3aFm4qtLHYCoEW1XJSkFaVaOMILCQAQxUHHA==",
|
||||
"requires": {
|
||||
"@davepagurek/bezier-path": "^0.0.7",
|
||||
"@japont/unicode-range": "^1.0.0",
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-walk": "^8.3.4",
|
||||
"colorjs.io": "^0.6.0",
|
||||
"escodegen": "^2.1.0",
|
||||
"gifenc": "^1.0.3",
|
||||
"i18next": "^19.0.2",
|
||||
"i18next-browser-languagedetector": "^4.0.1",
|
||||
"libtess": "^1.2.2",
|
||||
"omggif": "^1.0.10",
|
||||
"pako": "^2.1.0",
|
||||
"zod": "^4.2.1"
|
||||
}
|
||||
},
|
||||
"p5js-wrapper": {
|
||||
"version": "1.2.3",
|
||||
@@ -1236,8 +1532,20 @@
|
||||
"integrity": "sha512-nG4xiyydY7v+q0+/6wbE2gj+L7RPf3FDwM68govCcuyrBckXgrfDy+0SKCTNTGwbpypxjVAu5juU4XOlz4IRPw==",
|
||||
"requires": {
|
||||
"p5": "^1.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"p5": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/p5/-/p5-1.11.13.tgz",
|
||||
"integrity": "sha512-gfGo4AkyuNMs6Ko7UNFM9K2edqFRGyLrFaYUB+XXF127JVdEPu0BIaC5uDDNJpsRMOD9hJMUpsOH4HkfuNhvhA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"pako": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
|
||||
},
|
||||
"picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -1286,6 +1594,12 @@
|
||||
"@rolldown/pluginutils": "1.0.0-rc.17"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true
|
||||
},
|
||||
"source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
@@ -1322,6 +1636,11 @@
|
||||
"rolldown": "1.0.0-rc.17",
|
||||
"tinyglobby": "^0.2.16"
|
||||
}
|
||||
},
|
||||
"zod": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "p5js-vite",
|
||||
"name": "untitled-maze-game",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"babylonjs": "^9.5.1",
|
||||
"p5": "^2.2.3",
|
||||
"p5js-wrapper": "^1.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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 { startParticleSketch, stopParticleSketch } from "./p5_particles.js";
|
||||
import chestTextureUrl from "../img/img_chest.png";
|
||||
import wallTextureUrl from "../img/img_wall.png";
|
||||
import groundTextureUrl from "../img/img_ground.png";
|
||||
@@ -15,11 +16,7 @@ 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 p5GameOverPanel = document.getElementById("p5-game-over-panel");
|
||||
|
||||
const scene = new BABYLON.Scene(engine);
|
||||
scene.clearColor = new BABYLON.Color4(0.05, 0.07, 0.1, 1);
|
||||
@@ -77,8 +74,16 @@ function updateOverviewCameraForMaze(w, h) {
|
||||
|
||||
function showGameOverScreen() {
|
||||
gameOverActive = true;
|
||||
if (gameOverOverlay) {
|
||||
gameOverOverlay.hidden = false;
|
||||
const canvasStage = document.querySelector(".canvas-stage");
|
||||
if (canvasStage) {
|
||||
canvasStage.hidden = true;
|
||||
}
|
||||
if (p5GameOverPanel) {
|
||||
p5GameOverPanel.hidden = false;
|
||||
const sketchContainer = document.getElementById("p5-sketch-container");
|
||||
if (sketchContainer) {
|
||||
startParticleSketch(sketchContainer);
|
||||
}
|
||||
}
|
||||
if (document.pointerLockElement === canvas && document.exitPointerLock) {
|
||||
document.exitPointerLock();
|
||||
@@ -87,8 +92,13 @@ function showGameOverScreen() {
|
||||
|
||||
function hideGameOverScreen() {
|
||||
gameOverActive = false;
|
||||
if (gameOverOverlay) {
|
||||
gameOverOverlay.hidden = true;
|
||||
const canvasStage = document.querySelector(".canvas-stage");
|
||||
if (canvasStage) {
|
||||
canvasStage.hidden = false;
|
||||
}
|
||||
if (p5GameOverPanel) {
|
||||
p5GameOverPanel.hidden = true;
|
||||
stopParticleSketch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,22 @@ function randomizeSeed() {
|
||||
|
||||
// Update display from shared state
|
||||
function updateDisplay() {
|
||||
document.getElementById("status-seed").textContent = sharedState.config.seed;
|
||||
document.getElementById("status-level").textContent = sharedState.config.level;
|
||||
const statusSeed = document.getElementById("status-seed");
|
||||
const statusLevel = document.getElementById("status-level");
|
||||
const statusMazeSize = document.getElementById("status-maze-size");
|
||||
const statusChests = document.getElementById("status-chests");
|
||||
const statusTime = document.getElementById("status-time");
|
||||
const statusKey = document.getElementById("status-key");
|
||||
const statusRounds = document.getElementById("status-rounds");
|
||||
const statusMessage = document.getElementById("status-message");
|
||||
|
||||
if (!statusSeed || !statusLevel || !statusMazeSize || !statusChests || !statusTime || !statusKey || !statusRounds || !statusMessage) {
|
||||
console.warn("Some status display elements are missing from DOM");
|
||||
return;
|
||||
}
|
||||
|
||||
statusSeed.textContent = sharedState.config.seed;
|
||||
statusLevel.textContent = sharedState.config.level;
|
||||
|
||||
// Calculate effective maze size and chest count based on current level
|
||||
const roundScale = Math.max(0, sharedState.config.level - 1);
|
||||
@@ -38,32 +52,42 @@ function updateDisplay() {
|
||||
const effectiveHeight = Math.max(9, sharedState.config.mazeHeight + roundScale * 2);
|
||||
const effectiveChests = Math.max(1, sharedState.config.minChestDeadEnds + roundScale);
|
||||
|
||||
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);
|
||||
document.getElementById("status-key").textContent = sharedState.runtime.hasKey ? "yes" : "no";
|
||||
document.getElementById("status-rounds").textContent = sharedState.runtime.roundsCompleted;
|
||||
document.getElementById("status-message").textContent = sharedState.runtime.message;
|
||||
statusMazeSize.textContent = `${effectiveWidth}x${effectiveHeight}`;
|
||||
statusChests.textContent = effectiveChests;
|
||||
statusTime.textContent = sharedState.runtime.elapsedSeconds.toFixed(1);
|
||||
statusKey.textContent = sharedState.runtime.hasKey ? "yes" : "no";
|
||||
statusRounds.textContent = sharedState.runtime.roundsCompleted;
|
||||
statusMessage.textContent = sharedState.runtime.message;
|
||||
}
|
||||
|
||||
// Initialize event listeners
|
||||
document.getElementById("btn-start").addEventListener("click", () => {
|
||||
primeSfx();
|
||||
playSfx("click", 0.7);
|
||||
resetRun("Run started.");
|
||||
});
|
||||
const btnStart = document.getElementById("btn-start");
|
||||
const btnRestart = document.getElementById("btn-restart");
|
||||
const btnRandomize = document.getElementById("btn-randomize");
|
||||
|
||||
document.getElementById("btn-restart").addEventListener("click", () => {
|
||||
primeSfx();
|
||||
playSfx("click", 0.7);
|
||||
restartLevel("Level restarted.");
|
||||
});
|
||||
if (btnStart) {
|
||||
btnStart.addEventListener("click", () => {
|
||||
primeSfx();
|
||||
playSfx("click", 0.7);
|
||||
resetRun("Run started.");
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("btn-randomize").addEventListener("click", () => {
|
||||
primeSfx();
|
||||
playSfx("click", 0.7);
|
||||
randomizeSeed();
|
||||
});
|
||||
if (btnRestart) {
|
||||
btnRestart.addEventListener("click", () => {
|
||||
primeSfx();
|
||||
playSfx("click", 0.7);
|
||||
restartLevel("Level restarted.");
|
||||
});
|
||||
}
|
||||
|
||||
if (btnRandomize) {
|
||||
btnRandomize.addEventListener("click", () => {
|
||||
primeSfx();
|
||||
playSfx("click", 0.7);
|
||||
randomizeSeed();
|
||||
});
|
||||
}
|
||||
|
||||
// Update status display on game loop
|
||||
setInterval(() => {
|
||||
@@ -73,11 +97,17 @@ setInterval(() => {
|
||||
const effectiveHeight = Math.max(9, sharedState.config.mazeHeight + roundScale * 2);
|
||||
const effectiveChests = Math.max(1, sharedState.config.minChestDeadEnds + roundScale);
|
||||
|
||||
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);
|
||||
document.getElementById("status-key").textContent = sharedState.runtime.hasKey ? "yes" : "no";
|
||||
document.getElementById("status-rounds").textContent = sharedState.runtime.roundsCompleted;
|
||||
const statusMazeSize = document.getElementById("status-maze-size");
|
||||
const statusChests = document.getElementById("status-chests");
|
||||
const statusTime = document.getElementById("status-time");
|
||||
const statusKey = document.getElementById("status-key");
|
||||
const statusRounds = document.getElementById("status-rounds");
|
||||
|
||||
if (statusMazeSize) statusMazeSize.textContent = `${effectiveWidth}x${effectiveHeight}`;
|
||||
if (statusChests) statusChests.textContent = effectiveChests;
|
||||
if (statusTime) statusTime.textContent = sharedState.runtime.elapsedSeconds.toFixed(1);
|
||||
if (statusKey) statusKey.textContent = sharedState.runtime.hasKey ? "yes" : "no";
|
||||
if (statusRounds) statusRounds.textContent = sharedState.runtime.roundsCompleted;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
|
||||
120
src/p5_particles.js
Normal file
120
src/p5_particles.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import p5 from "p5";
|
||||
import gameOverImageUrl from "../img/img_jobapplication.png";
|
||||
|
||||
let sketch;
|
||||
|
||||
export function startParticleSketch(containerElement) {
|
||||
if (sketch) {
|
||||
sketch.remove();
|
||||
}
|
||||
|
||||
sketch = new p5((p) => {
|
||||
let particles = [];
|
||||
let gameOverImg;
|
||||
const imgSize = 50;
|
||||
const particleCount = 15;
|
||||
|
||||
p.setup = async function() {
|
||||
const width = containerElement.clientWidth || 800;
|
||||
const height = containerElement.clientHeight || 600;
|
||||
console.log("p5 setup:", { width, height });
|
||||
|
||||
const canv = p.createCanvas(width, height);
|
||||
canv.parent(containerElement);
|
||||
|
||||
// Load image asynchronously
|
||||
try {
|
||||
gameOverImg = await p.loadImage(gameOverImageUrl);
|
||||
console.log("Game over image loaded:", gameOverImg.width, "x", gameOverImg.height);
|
||||
} catch (err) {
|
||||
console.error("Failed to load particle image:", err);
|
||||
}
|
||||
|
||||
// Initialize particles with random starting positions
|
||||
for (let i = 0; i < particleCount; i++) {
|
||||
particles.push({
|
||||
x: p.random(width),
|
||||
y: p.random(height),
|
||||
vx: p.random(-2, 2),
|
||||
vy: p.random(-2, 2),
|
||||
life: 200,
|
||||
rotation: p.random(p.TWO_PI),
|
||||
rotationSpeed: p.random(-0.08, 0.08),
|
||||
scale: p.random(0.7, 1.3),
|
||||
});
|
||||
}
|
||||
console.log("Particles initialized:", particles.length);
|
||||
};
|
||||
|
||||
p.draw = function() {
|
||||
// Draw background image full screen
|
||||
if (gameOverImg) {
|
||||
p.imageMode(p.CORNER);
|
||||
p.image(gameOverImg, 0, 0, p.width, p.height);
|
||||
}
|
||||
|
||||
// Semi-transparent overlay for visibility
|
||||
p.background(0, 0, 0, 20);
|
||||
|
||||
for (let i = 0; i < particles.length; i++) {
|
||||
const part = particles[i];
|
||||
|
||||
// Update position
|
||||
part.x += part.vx;
|
||||
part.y += part.vy;
|
||||
part.rotation += part.rotationSpeed;
|
||||
|
||||
// Bounce off walls with friction
|
||||
if (part.x < 0 || part.x > p.width) {
|
||||
part.vx *= -0.8;
|
||||
part.x = p.constrain(part.x, 0, p.width);
|
||||
}
|
||||
if (part.y < 0 || part.y > p.height) {
|
||||
part.vy *= -0.8;
|
||||
part.y = p.constrain(part.y, 0, p.height);
|
||||
}
|
||||
|
||||
// Add some gravity
|
||||
part.vy += 0.1;
|
||||
part.vy = p.constrain(part.vy, -5, 5);
|
||||
|
||||
// Randomly change direction slightly
|
||||
if (p.random() < 0.03) {
|
||||
part.vx += p.random(-0.5, 0.5);
|
||||
part.vy += p.random(-0.5, 0.5);
|
||||
part.vx = p.constrain(part.vx, -3, 3);
|
||||
part.vy = p.constrain(part.vy, -3, 3);
|
||||
}
|
||||
|
||||
// Draw particle
|
||||
p.push();
|
||||
p.translate(part.x, part.y);
|
||||
p.rotate(part.rotation);
|
||||
p.scale(part.scale);
|
||||
if (gameOverImg) {
|
||||
p.imageMode(p.CENTER);
|
||||
p.tint(255, 200);
|
||||
p.image(gameOverImg, 0, 0, imgSize, imgSize);
|
||||
}
|
||||
p.pop();
|
||||
}
|
||||
};
|
||||
|
||||
p.windowResized = function() {
|
||||
if (containerElement && containerElement.offsetParent !== null) {
|
||||
const width = containerElement.clientWidth;
|
||||
const height = containerElement.clientHeight;
|
||||
if (width > 0 && height > 0) {
|
||||
p.resizeCanvas(width, height);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function stopParticleSketch() {
|
||||
if (sketch) {
|
||||
sketch.remove();
|
||||
sketch = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user