|
|
||
|---|---|---|
| src | ||
| vendor | ||
| README.md | ||
| editor.html | ||
| index.html | ||
| start_web.sh | ||
README.md
Escape
A Wolfenstein-3D-style raycaster game built with Phaser 4. The "3D" is an authentic raycasting engine: a 2D grid rendered as vertical wall strips. Graphics are intentionally stubbed (solid colors / placeholder shapes) so you can drop in your own spritesheets later.
Run
There is no build step and no npm dependency. The game is plain ES-module
JavaScript; Phaser ships vendored in vendor/. Serve the folder with any static
HTTP server and open it in a modern browser (Chrome/Edge/Firefox/Safari — needs
import map support, ~2023+).
./start_web.sh # python3 -m http.server 3000
# or any equivalent:
# npx serve .
# php -S localhost:3000
# (drop the folder behind nginx / Apache / GitHub Pages / S3 / …)
Then open:
- Game: http://localhost:3000/
- Editor: http://localhost:3000/editor.html
Opening the files via
file://will not work — ES modules require an HTTP origin. Any static server (above) is enough; no server-side code runs.
Game controls
| Action | Keys |
|---|---|
| Move / strafe | W A S D (arrows also move) |
| Turn | ← →, or mouse (click to lock) |
| Shoot | Left-click (mouse locked) / Space |
The HUD shows health, ammo, and score. Walk over pickups to collect them; shoot guards to score. Click the view once to capture the mouse for look controls.
Level editor (/editor.html)
- Palette (top): pick a wall tile, the player Start marker, or an entity.
- Left-click / drag: paint the selected brush.
- Right-click / drag: erase (clears the tile and any entity in the cell).
- Arrow keys: scroll the view. Middle-drag: pan. Mouse wheel: zoom.
- New: start a fresh blank grid (default 72×72; see
NEW_LEVEL_WIDTH/HEIGHTinsrc/engine/constants.js). Save: persist to browser storage. Export/Import JSON: files on disk. - Play Test: opens the game in a new tab running your current level.
The grid is large enough to build big levels; only the on-screen cells are drawn, so bigger maps stay fast. Scroll with the arrow keys as your level grows past the visible area.
Place an Exit entity in a level so the player can finish it; walking onto the exit advances to the next level in the campaign (see below). A level with no exit instead completes when every guard is defeated.
Level file format
Levels are plain JSON — exactly what the editor's Export JSON writes and what
the game reads. To author levels, paint one in the editor, Export it, and drop
the file in src/levels/ (see the campaign section). The format is:
{
"version": 1, // schema version (stamped on export)
"name": "Dungeon Entrance", // display name; also the export filename
"width": 16, // grid columns
"height": 16, // grid rows
"tiles": [ /* … */ ], // row-major ints, length MUST equal width*height
// 0 = floor; 1..5 = wall tiles (constants.js TILES)
"playerStart": { "x": 2.5, "y": 3.5, "dir": 0 }, // cell units; dir in radians
"entities": [ // may be empty
{ "type": "enemy", "x": 8.5, "y": 5.5 },
{ "type": "ammo", "x": 4.5, "y": 4.5 },
{ "type": "health", "x": 6.5, "y": 9.5 },
{ "type": "treasure", "x": 12.5, "y": 2.5 },
{ "type": "exit", "x": 14.5, "y": 8.5 }
]
}
entity.type and tile ids come from the registries in src/engine/constants.js.
Files are validated on load (parseLevel): tiles.length must equal
width*height and playerStart must be present; unknown tile/entity ids fail
safe rather than crashing.
Campaign — using your files as game levels
The game plays the level files listed, in order, in the manifest
src/levels/levels.json:
{
"levels": ["level1.json", "level2.json"]
}
To add a level: drop its .json in src/levels/ and add its filename to the
levels array. Reaching an Exit advances to the next file; after the last
one the player sees a victory screen. Health, ammo, and score carry across
levels. If the manifest can't be fetched, the game falls back to the bundled
level1.data.js.
Project layout
index.html Game page (import map → vendored Phaser)
editor.html Editor page (import map → vendored Phaser)
vendor/ phaser.esm.min.js (vendored so no npm install is needed)
src/
engine/ Shared core: constants (TILE & entity registries), GameMap,
Raycaster (DDA + ZBuffer), SpriteRenderer, Player, Entity, levelIO
game/ Phaser bootstrap + Boot/Game/Hud scenes
editor/ Phaser bootstrap + EditorScene
levels/ levels.json (campaign manifest), level1.json / level2.json (levels),
level1.data.js (bundled offline fallback, kept in sync with level1.json)
The game and editor are separate HTML entry points that share everything in
src/engine, so a level you paint is exactly what plays. Native ES modules mean
every relative import includes its .js extension, and the bare phaser
specifier is resolved by the <script type="importmap"> block in each HTML file.
Updating Phaser
vendor/phaser.esm.min.js is a copy of Phaser's official ESM build. To update,
download the matching dist/phaser.esm.min.js from the
Phaser release (or npm pack phaser) and replace the file — no other changes needed.
Where to extend next
- Textures: swap the solid-color strip in
engine/Raycaster.jsand the billboardfillRectinengine/SpriteRenderer.jsfordrawImageof your spritesheet frames. Tile ids already map 1:1 to a texture index. - Enemy AI: flesh out
Entity.update()(patrol → chase → attack). - Doors / keys: tile id 5 is flagged
isDoorinengine/constants.js; wire sliding + locked-door logic intoGameMap/Raycaster. - Sound, multiple levels, menus: hook into the scenes in
src/game.