Compare commits

..

3 Commits

Author SHA1 Message Date
pobadoba
151d2ed596 final fixes and readme 2026-05-10 23:33:56 +09:00
pobadoba
7f6548d9fb update readme 2026-05-10 23:04:01 +09:00
pobadoba
6532387f59 docs: Standardize module documentation and focus on final product
- Added complete documentation for state.js, maze.js, grid.js, sfx.js
  (was: 'Already Well-Structured — No Changes')
- Removed 'Refactoring Summary' section (process-focused content)
- Restructured 'Design Decisions & Rationale' to document current architecture
  rather than refactoring journey
- Updated 'AI Assistance' section to mention refactoring work in context
  of overall development
- Simplified 'Files Structure' legend to remove distinction between
  refactored and original modules
- All 14 modules now documented consistently with Purpose/Functions/Benefits

Result: Documentation now explains the final product cleanly without the
'something changed' narrative, while preserving context of development work.
2026-05-10 22:33:56 +09:00
5 changed files with 191 additions and 387 deletions

View File

@@ -1,212 +0,0 @@
# Untitled Maze Game - ID30011 Midterm Project Proposal (Revised)
- **Name:** Bumgyu Suh
- **Student ID:** 20240905
- **Repository URL:** https://git.prototyping.id/20240905/homework5
- **Engine:** Babylon.js
## 1. Project Summary
Untitled Maze Game is a 3D first-person dungeon maze game. Each level generates a new maze, and the player must find the key hidden in one chest, then reach the exit area to progress.
Main twist:
- Opening a chest that has already been opened in the current level causes immediate game over.
- This memory pressure creates the core challenge.
Scoring tracked for now:
- Total time spent
- Progress (level reached)
## 2. Finalized Design Decisions
These are locked decisions for implementation:
1. Chest reset scope:
- Opened chest state resets every level.
2. Chest interaction:
- Player must left click while targeting a chest.
- Interaction prompt shown: "Click to open chest" when chest is targetable.
3. Maze topology:
- Maze is allowed to contain loops (not necessarily a perfect maze).
- Each level must guarantee a minimum number of dead-end cells with chests.
- Additional dead-ends without chests are allowed.
4. Difficulty scaling:
- Increase maze width and height by level.
- Lighting settings stay fixed (no light-based difficulty scaling).
5. Win condition:
- Exit is a highlighted zone/area.
- Entering exit zone with key automatically transitions to next level.
6. Visual implementation order:
- Start with primitive meshes for all gameplay-critical elements.
## 3. Gameplay Rules
## Objective
- Search chests to find the key.
- Avoid reopening previously opened chests in that level.
- Reach exit area after obtaining key.
- Clear levels as fast as possible.
## Win / Lose Conditions
- Win level: player enters exit zone while holding key.
- Soft block: entering exit without key shows message and does not transition.
- Lose run: player opens a chest already opened in current level.
## Player Controls
- `W/A/S/D`: movement
- Mouse: look direction
- Left click: open chest when targeted
## 4. Technical Architecture Plan
To keep implementation clean, split into four layers:
1. Maze Logic Layer (pure functions)
- Generate grid layout
- Detect dead-ends
- Place chests, key chest, exit, and spawn
- Return plain data only
2. Game State Layer
- Track current level
- Track timer / elapsed time
- Track hasKey
- Track chest open state (per level)
- Resolve win/lose transitions
3. Babylon Scene Layer
- Build meshes from grid
- Configure first-person camera and collisions
- Handle raycast/pick chest targeting and click interaction
- Render highlighted exit zone
4. UI Layer
- HUD: level, time, key possession, prompt/status text
- Messages: wrong chest, key found, find key first, game over, level clear
## 5. Data Model (Revised)
Use separate static and dynamic state instead of overloading one numeric ID.
## Static cell data
- `cellType`: wall | path | chest | exit | spawn
## Dynamic state
- `openedChests`: set/map keyed by cell coordinate
- `keyChestCoord`: coordinate of the one correct chest
- `hasKey`: boolean
Benefits:
- Cleaner logic
- Easier debugging
- Lower chance of state bugs from mixed meanings
## 6. Level Generation Specification
Per level:
1. Compute maze dimensions from level number.
2. Generate a solvable maze grid (loops allowed).
3. Find dead-end candidates.
4. Place at least `minChestDeadEnds` chests on dead-ends.
5. Choose one chest as key chest.
6. Choose one exit location (highlighted zone).
7. Choose valid spawn point.
8. Validate reachability:
- Spawn can reach key chest
- Spawn (after key) can reach exit
If validation fails, regenerate.
## 7. Babylon.js Implementation Notes
- Camera: use first-person style camera (for example `UniversalCamera`) with pointer lock.
- Collision: enable gravity/collision with wall meshes.
- Interaction: center-screen ray pick + left click.
- Chest meshes: primitive boxes in MVP.
- Exit zone: highlighted plane or emissive ground area.
- Keep one scene; rebuild level meshes on level transition.
## 8. MVP Checklist (Implementation Order)
## Phase A - Core scaffold
- [ ] Refactor current Babylon template into modular files/functions.
- [ ] Add first-person camera controls and pointer lock.
- [ ] Add movement collision against wall meshes.
## Phase B - Maze system
- [ ] Implement maze generation with loops allowed.
- [ ] Implement dead-end detection.
- [ ] Implement chest placement with minimum dead-end chest count.
- [ ] Implement key chest assignment and exit placement.
- [ ] Implement reachability validation and regenerate on failure.
## Phase C - Gameplay rules
- [ ] Implement per-level chest open tracking.
- [ ] Implement chest click interaction and "Click to open chest" prompt.
- [ ] Implement outcomes: wrong chest / key found / reopened chest game over.
- [ ] Implement exit-zone behavior: block without key, auto-next-level with key.
## Phase D - UI and scoring
- [ ] Display level number.
- [ ] Display elapsed total time.
- [ ] Display key possession status.
- [ ] Display gameplay feedback messages.
## Phase E - Level progression
- [ ] Increase maze width/height per level.
- [ ] Reset per-level state correctly on transition.
- [ ] Preserve run-level state (time, current level progression).
## 9. Testing Checklist
- [ ] Reopening an opened chest always ends run.
- [ ] Chest-open state resets at new level.
- [ ] Entering exit without key never transitions.
- [ ] Entering exit with key always transitions.
- [ ] Every generated level is solvable.
- [ ] Minimum chest dead-end count is always satisfied.
- [ ] Performance remains stable across first several levels.
## 10. Assets Plan
Immediate plan (MVP):
- Use primitives for wall, floor, chest, and exit zone.
- Use simple material colors to distinguish gameplay objects.
Prepare soon (after core loop works):
- Tileable wall texture
- Tileable floor texture
- Chest texture/material
- Basic SFX set:
- chest open
- wrong chest
- key found
- level clear
- game over
Optional polish later:
- Better chest model
- Exit marker model
- Ambient loop audio
## 11. Class Concept Coverage
This project uses:
- JavaScript arrays and object state
- Functional decomposition in generation pipeline
- Event handling (keyboard/mouse)
- External library usage (Babylon.js)
- Real-time tracking (elapsed time HUD)
## 12. Scope Guardrails
To keep delivery reliable:
- Prioritize clean gameplay loop over art polish.
- Keep lighting simple and fixed.
- Do not add non-essential mechanics before MVP checklist is complete.

355
README.md
View File

@@ -10,33 +10,36 @@
- **Student ID:** 20240905
- **Student Email:** bumgyu@kaist.ac.kr
- **Repository URL:** https://git.prototyping.id/20240905/Untitled-Maze-Game
- **Video Demonstration:** [YouTube Link]
- **Video Demonstration:** https://youtu.be/8LDcLpsNJck (turn on youtube subtitles)
- **Play Link:** https://pobadoba.com/games/maze
---
## Game Overview
### Concept
**Untitled Maze Game** is a 3D first-person maze escape game built with Babylon.js and p5.js. Players must navigate procedurally-generated mazes in a race against time, collecting a key and finding the exit within 60 seconds, but there's a twist! You must not open a chest that you have already opened before! Each successful round increases difficulty—maze size grows, more chests appear, and players advance to the next level. If you fail... there is a little surprising waiting for you.
**Untitled Maze Game** is a 3D first-person maze escape game built with Babylon.js and p5.js. Players must navigate procedurally-generated mazes in a race against time, collecting a key and finding the exit within 60 seconds, but there's a twist! You must not open a chest that you have already opened before! Each successful round increases difficulty—maze size grows, more chests appear, and players advance to the next level. If you fail... there is a little surprising waiting for you (made with p5.js).
### Gameplay Flow
```
START SCREEN (img_start.png)
START SCREEN
↓ Press R
GAMEPLAY (60 seconds)
↙ Time Up / Found Exit ↖
GAME OVER NEXT LEVEL
(img_jobapplication.png + Particles)
GAME OVER NEXT LEVEL
(Job Application
Jumpscare)
```
### How to Play
0. **Project Setup:** Run the commands: `npm install`, then `npm run dev` in the project repository top folder; alternatively, access the game in [this website](https://pobadoba.com/games/maze)
1. **Start the Game:** Press **R** on the start screen to begin
2. **Navigate:** Use **WASD** to move, mouse to look around
3. **Find the Key:** **Left-Click** chests until you find the key, do not click on a chest you have opened before.
3. **Find the Key:** **Left-Click** chests until you find the key, do not click on a chest you have opened before (leads to game over)
4. **Reach the Exit:** Once you have the key, reach the exit door
5. **Survive the Time:** You have 60 seconds per round. Time runs out = Game Over
5. **Survive the Time:** You have 60 seconds per round. Time runs out = Game Over (Job Application Jumpscare ending)
6. **Progress:** Successfully exiting unlocks the next level with a larger maze and more chests
### Controls
@@ -56,10 +59,9 @@ GAME OVER NEXT LEVEL
## Code Documentation
### Packages Used
- **3D Graphics:** Babylon.js v9.5.1 (3D scene, camera, meshes, rendering)
- **Bundler:** Vite v8.0.10 (ES6 modules, asset optimization)
- **2D Graphics:** p5.js v2.x (particle effects for game-over screen)
- **Audio:** Web Audio API (polyphonic sound effects)
- **3D Graphics:** Babylon.js (3D scene, camera, meshes, rendering)
- **2D Graphics:** p5.js (particle effects for game-over screen)
- **Audio:** Web Audio API
### Files Structure
@@ -67,12 +69,12 @@ GAME OVER NEXT LEVEL
src/
├── babylon_panel.js # Game orchestrator (scene init, controller, API)
├── html_panel.js # Debug UI state management
├── p5_particles.js # Particle effects for start/game-over screens
├── p5_particles.js # Particle effects for game over screen
├── game/
│ ├── state.js # Shared game state (config + runtime)
│ ├── maze.js # Procedural maze generation (seeded RNG)
│ ├── grid.js # Coordinate conversion, collision helpers
│ ├── sfx.js # Sound effect playback system
│ ├── state.js # Shared game state (config + runtime)
│ ├── maze.js # Procedural maze generation (seeded RNG)
│ ├── grid.js # Coordinate conversion, collision helpers
│ ├── sfx.js # Sound effect playback system
│ ├── scene-init.js # Babylon.js engine & scene initialization
│ ├── camera-manager.js # Camera creation, mode switching, updates
│ ├── game-loop.js # Main render loop, game state machine
@@ -108,9 +110,12 @@ sfx/
└── sfx_chest_close.wav # Chest closing sound
```
**Legend:**
- ✓ Unchanged from original (already well-structured)
- Without checkmark = newly extracted/refactored
**Module Organization:**
- **game/**: Core game logic (state, generation, collision, audio)
- **controls/**: Input and event handling
- **assets/**: Reusable factories (materials, textures)
- **ui/**: Visual feedback (HUD, overlays)
- Root level (babylon_panel.js): Main script that ties everything together
### Core Modules
@@ -123,7 +128,7 @@ sfx/
- Input handler registration via `setupInputHandlers()`
- Game loop registration via `registerGameLoop()`
- Screen transitions via `showGameOverScreen()`, `hideGameOverScreen()`, etc.
- Level generation orchestration
- Level generation coordination
- State management and API exposure
**Key Flow:**
@@ -132,7 +137,7 @@ Page Load → babylon_panel.js
↓ initialize scene, cameras, sphere
↓ setupInputHandlers() → register keyboard/pointer events
↓ registerGameLoop() → register frame-by-frame updates
↓ showStartScreen() → p5 particle sketch
↓ showStartScreen()
↓ (user presses R)
↓ startRunFromStartScreen() → generateLevel()
↓ (gameplay loop runs until win/lose)
@@ -152,7 +157,7 @@ Page Load → babylon_panel.js
**Benefits:**
- Encapsulates Babylon.js boilerplate
- Easier to swap or test rendering configuration
- Decouples orchestrator from engine details
- Decouples main scene runner from engine details
#### 3. **game/camera-manager.js** (Camera Management)
**Purpose:** First-person and overview camera creation and switching
@@ -289,51 +294,114 @@ Page Load → babylon_panel.js
- Reusable styling/animation controls
- Can easily add new HUD elements
#### 11. **game/state.js** (Shared State)
**Already Well-Structured — No Changes**
Centralized game configuration and runtime state
#### 11. **game/state.js** (Shared State)
**Purpose:** Centralized game state management to prevent coupling between modules
#### 12. **game/maze.js** (Procedural Generation) ✓
**Already Well-Structured — No Changes**
Recursive backtracking with seeded RNG
**Structure:**
```javascript
window.mazeGameState = {
config: {
seed, // Reproducible maze generation
level, // Current progression level
mazeWidth: 11, // Base width (increases per level)
mazeHeight: 11, // Base height
minChestDeadEnds: 2 // Min chests to place
},
runtime: {
runActive, // Is gameplay active?
hasKey, // Player collected key?
roundsCompleted, // Levels completed this run
elapsedSeconds, // Countdown timer (60 → 0)
message // Status text for HUD
}
}
```
#### 13. **game/grid.js** (Coordinate Utilities) ✓
**Already Well-Structured — No Changes**
Grid-to-world conversions and walkability checks
**Benefits:**
- Single source of truth for all game state
- All modules read/write to same object (no data duplication)
- Easy to serialize/save game state
- Enables time-travel debugging via console inspection
#### 14. **game/sfx.js** (Audio System) ✓
**Already Well-Structured — No Changes**
ES6 import-based audio loading and playback
#### 12. **game/maze.js** (Procedural Generation)
**Purpose:** Generate solvable, deterministic mazes using seeded randomization
**Functions:**
- `seededRng(seed)` — Deterministic random number generator (same seed = same sequence)
- `generateMazeGrid(w, h, seed)` — Recursive backtracking maze algorithm
- `findDeadEnds(grid)` — Locate dead-end cells for chest/exit placement
**Algorithm:**
Recursive backtracking with seeded RNG ensures:
- Every maze is solvable (connected)
- Same seed produces identical maze (perfect for replays)
- Configurable difficulty (width/height parameters)
**Benefits:**
- Deterministic yet varied level generation
- No performance issues (pre-computed before rendering)
- Perfect reproducibility for competitive play
#### 13. **game/grid.js** (Coordinate Utilities)
**Purpose:** Convert between grid coordinates and 3D world space for collision detection
**Functions:**
- `gridCellToWorld(grid, x, y, cellSize)` — Grid cell → world position (returns `{x, z}`)
- `isWalkableCell(grid, x, y)` — Check if cell is navigable (not a wall)
**Key Insight:**
Mazes are generated as 2D grids (1 = wall, 0 = path). This module bridges the gap between grid coordinates used by `maze.js` and 3D world positions used by `level-generator.js`.
**Benefits:**
- Decouples grid logic from spatial positioning
- Makes collision detection and pathfinding calculations simpler
- Reusable for any grid-based game mechanic
#### 14. **game/sfx.js** (Audio System)
**Purpose:** Load and playback polyphonic sound effects with Web Audio API
**Functions:**
- `playSfx(name, volume)` — Play a sound effect by name (cloned for polyphony)
- `primeSfx()` — Initialize audio context (required by browser for first sound)
**Audio Files** (imported via ES6, bundled by Vite):
```javascript
import clickUrl from "../../sfx/sfx_click.wav"
import chestOpenUrl from "../../sfx/sfx_chest_open.wav"
import chestCloseUrl from "../../sfx/sfx_chest_close.wav"
import keyUrl from "../../sfx/sfx_key.wav"
import clockUrl from "../../sfx/sfx_clock.wav"
import stepUrl from "../../sfx/sfx_step.wav"
import winUrl from "../../sfx/sfx_win.wav"
import loseUrl from "../../sfx/sfx_lose.wav"
```
**Polyphony via Cloning:**
Each call to `playSfx()` clones the audio node, allowing multiple sounds to play simultaneously (e.g., footsteps + clock alarm).
**Benefits:**
- Polyphonic sound effects (no cutting each other off)
- Browser-compatible audio context priming
- Centralized audio management (easy to add volume controls, reverb, etc.)
---
## Key Features & Implementation Details
| Feature | Implementation | Status |
|---------|----------------|--------|
| **3D Rendering** | Babylon.js UniversalCamera, procedural mesh generation | ✓ Complete |
| **Procedural Mazes** | Seeded random generation with configurable dimensions | ✓ Complete |
| **Time-Attack Mode** | 60-second countdown timer with auto-game-over on timeout | ✓ Complete |
| **Progressive Difficulty** | Maze size & chest count increase per completed level | ✓ Complete |
| **Collision Detection** | Raycasting for chest interaction, sphere collision for exit | ✓ Complete |
| **Sound System** | 8 polyphonic SFX with Web Audio API and context priming | ✓ Complete |
| **Particle Effects** | p5.js animated particles with physics on game-over screen | ✓ Complete |
| **Start Screen** | Full-screen p5.js panel with img_start.png background | ✓ Complete |
| **Game-Over Screen** | Full-screen overlay with job application image + particles | ✓ Complete |
| **Visual Warnings** | Red pulsing timer + clock sound when time < 10 seconds | ✓ Complete |
| **Camera Modes** | First-person (WASD + mouse) and overhead (overview) | ✓ Complete |
| **Responsive Layout** | Full-screen canvas with bottom-overlay debug controls | ✓ Complete |
### 🔧 Technical Highlights
**Browser Compatibility:**
- Audio context requires user interaction priming via `primeSfx()`—automatically triggered on first W/A/S/R key press
**Performance Optimizations:**
- Vite's ES6 module bundling and tree-shaking
- Asset optimization (textures, audio)
- Efficient raycasting for chest targeting (not per-pixel)
- Single draw call per maze (not per cell)
| Feature | Implementation |
|---------|----------------|
| **3D Rendering** | Babylon.js UniversalCamera, procedural mesh generation |
| **Procedural Mazes** | Seeded random generation with configurable dimensions |
| **Time-Attack Mode** | 60-second countdown timer with auto-game-over on timeout |
| **Progressive Difficulty** | Maze size & chest count increase per completed level |
| **Collision Detection** | Raycasting for chest interaction, sphere collision for exit |
| **Sound System** | polyphonic sound effects with Web Audio API |
| **Particle Effects** | p5.js animated particles with physics on game-over screen |
| **Start Screen** | Full-screen p5.js panel with starting image |
| **Game-Over Screen** | Full-screen overlay with job application image + particles |
| **Visual Warnings** | Red pulsing timer + clock sound when time < 10 seconds |
| **Camera Modes** | First-person (WASD + mouse) and overhead orbital view |
| **Responsive Layout** | Full-screen canvas with bottom-overlay debug controls |
**Code Quality Patterns:**
- **Shared State Pattern:** `window.mazeGameState` prevents data coupling across modules
@@ -341,116 +409,56 @@ ES6 import-based audio loading and playback
- **Observer Pattern:** `registerBeforeRender()` for frame-synchronized updates
- **Async/Await:** p5.js async image loading for non-blocking resource loading
---
## Known Issues & Limitations
### ⚠️ Known Problems
**Known Problems**
1. **Pointer Lock Exit:** Pointer lock may be annoying for newcomers to web browser games
2. **Chunk Size Warning:** Built JavaScript is ~9.1 MB due to image assets
- Not an issue for local play
### ⭐ Special Features to Note
- **Seeded Randomization:** Players can use the same seed to replay identical mazes (debug button: "Randomize seed")
- **Low-Time Audio Feedback:** Clock sound triggers once when time drops below 10 seconds (prevents spam)
- **Full-Screen Transitions:** Start screen, gameplay, and game-over have full-screen p5.js overlays for immersive presentation
- **Difficulty Scaling Formula:** Mathematically designed to keep progression challenging but fair
---
## Refactoring Summary (Phase 3 Complete)
### Code Metrics
| Metric | Before | After | Change |
|--------|--------|-------|--------|
| Main file (babylon_panel.js) | 570 lines | 195 lines | -66% |
| Total source files | 5 | 14 | +9 new modules |
| Build modules | 355 | 364 | +9 (new files) |
| Cyclomatic complexity | High | Low | Each module < 20 lines avg |
### Dependency Graph
```
babylon_panel.js (Orchestrator)
├── game/scene-init.js
├── game/camera-manager.js
├── controls/input-handler.js
│ └── game/sfx.js
├── game/level-generator.js
│ ├── game/maze.js
│ ├── game/grid.js
│ └── assets/materials.js
├── game/game-loop.js
│ ├── game/sfx.js
│ ├── game/collisions.js
│ └── ui/hud.js
├── game/screen-manager.js
│ └── p5_particles.js
└── game/state.js (shared by all)
```
### Module Characteristics
- **No circular dependencies:** Each module imports only from modules below it
- **Shared state:** All modules read/write `window.mazeGameState` (single source of truth)
- **Event-driven:** Input → callbacks → state update → HUD refresh
- **Callback pattern:** Higher modules pass callbacks to lower modules for decoupling
### Refactoring Safety Checklist
**Build tested:** `npm run build` completes with 364 modules, no errors
**No breaking changes:** `window.mazeGameApi.generateLevel()` still exported
**Audio bundling intact:** All 8 SFX files in dist/assets/ with hashes
**Backwards compatible:** All gameplay mechanics unchanged
**No new dependencies:** Uses existing npm packages only
**ESM imports work:** Vite resolves all relative paths correctly
### Next Steps for Future Maintenance
1. **Add new interaction types:** Extend `game/collisions.js` with new raycasts
2. **Add gamepad support:** Extend `controls/input-handler.js` with gamepad listeners
3. **Add new screens:** Add functions to `game/screen-manager.js`
4. **Add new camera modes:** Extend `game/camera-manager.js` with new camera types
5. **Add sound designer tools:** Extend `game/sfx.js` with volume/pan controls
---
## Design Decisions & Rationale
### Refactoring Strategy (Phase 3 Complete)
**Objective:** Improve code maintainability without breaking gameplay
### 1. Modular Architecture with Separation of Concerns
**Decision:** Organize code into 14 focused modules rather than monolithic files
**Approach:** Modular separation of concerns by extracting 9 new modules from the original monolithic `babylon_panel.js` (570 lines → 195 lines).
**Rationale:**
- Each module has a single responsibility (scene setup, input handling, collision detection, etc.)
- No circular dependencies — clean dependency flow from orchestrator down to utilities
- Easier to test, debug, and extend individual features
- New developers can understand one module without understanding the whole codebase
- Easy to add features: extend relevant modules instead of modifying monolithic files
#### Why This Structure?
**Architecture Pattern:**
```
babylon_panel.js (orchestrator) ← high-level control
├→ game/scene-init.js ← rendering setup
├→ game/camera-manager.js ← camera control
├→ controls/input-handler.js ← event routing
├→ game/level-generator.js ← spatial layout
├→ game/game-loop.js ← frame updates
├→ game/screen-manager.js ← UI transitions
└→ game/state.js ← shared data (all modules)
```
| Module | Benefit |
|--------|---------|
| **scene-init.js** | Isolate Babylon.js boilerplate from game logic |
| **camera-manager.js** | Encapsulate complex camera configuration; easy to test/add modes |
| **level-generator.js** | Pure spatial functions; reusable for future level types |
| **game-loop.js** | Frame-by-frame logic visible in one place; easier to debug timing |
| **collisions.js** | Isolated raycasting; reusable for new interaction types |
| **input-handler.js** | Centralized event routing; easy to add gamepad/mobile controls |
| **screen-manager.js** | p5 lifecycle management; easy to add new screens (pause, level intro) |
| **materials.js** | Texture setup reusable by other systems; centralized configuration |
| **hud.js** | DOM updates separate from game state; CSS animations cleanly decoupled |
### 2. Shared State Pattern via window.mazeGameState
**Decision:** Centralize all game state in single `window.mazeGameState` object
#### Testing Benefits
- **Unit testable:** Each module has single responsibility, minimal dependencies
- **Integration testable:** Callbacks allow mocking of complex systems
- **Less fragile:** Changing one concern doesn't require refactoring others
#### Developer Experience
- **Faster onboarding:** New developers can understand features one module at a time
- **Feature additions:** Adding chests, NPCs, traps only requires extending relevant modules
- **Debugging:** Isolating bugs is easier when concerns are separated
### Original Design Decisions (Unchanged)
**Decision:** Isolate game state in `game/state.js` rather than scatter variables globally
**Rationale:**
**Rationale:**
- Prevents tight coupling between UI, physics, and rendering systems
- All modules read/write from same source of truth (no data duplication)
- Simplifies debugging (inspect state in console at any time)
- Enables hot-reloading during development
- Simplifies debugging (single place to inspect game state)
#### 2. Babylon.js Over Three.js
### 3. Callback-Based Event Routing
**Decision:** Lower modules don't know about higher modules; communication via callbacks
**Rationale:**
- Reduces coupling between layers
- Easy to mock/test: pass different callbacks to change behavior
- Flexible event handling: same module used for different purposes
- Example: `registerGameLoop(scene, state, callbacks)` doesn't know about UI — it just calls callbacks
### 4. Babylon.js Over Three.js
**Decision:** Used Babylon.js for 3D graphics
**Rationale:**
@@ -459,7 +467,7 @@ babylon_panel.js (Orchestrator)
- Efficient mesh instancing for maze cells
- Excellent documentation for procedural generation
#### 3. p5.js for Particle Effects
### 5. p5.js for Particle Effects
**Decision:** Delegated particle rendering to p5.js instead of Babylon.js
**Rationale:**
@@ -468,7 +476,7 @@ babylon_panel.js (Orchestrator)
- Easy to swap/experiment with particle physics without affecting core game
- Full-screen 2D canvas doesn't compete with 3D rendering pipeline
#### 4. Time-Attack Mode (vs. Exploration, Level Editing)
### 6. Time-Attack Mode (vs. Exploration, Level Editing)
**Decision:** 60-second countdown instead of unlimited time
**Rationale:**
@@ -476,31 +484,34 @@ babylon_panel.js (Orchestrator)
- Enables meaningful progression (faster times unlock harder mazes)
- Reduces scope (no need for complex AI, item management, etc.)
### 7. Procedural Maze Generation with Seeded RNG
**Decision:** Use seeded random number generator for deterministic maze generation
**Rationale:**
- Varied layouts via different seeds (infinite replayability)
- Better than storing pre-made levels (scalable to any difficulty)
- Recursive backtracking ensures every maze is solvable
---
## Help from AI & Resources
### AI Assistance
- **GitHub Copilot:** Used for code structure review and refactoring suggestions
- Suggested separating static maze data from dynamic game state (instead of coupling both in a single 2D array)
- Helped organize modules into logical file structure
- Reviewed p5.js particle physics for correctness
- **GitHub Copilot:** Used throughout development for code quality, structure, and refactoring
- **Early Development:** Suggested separating static maze data from dynamic game state (prevents coupling)
- **Module Organization:** Proposed logical file structure to improve maintainability
- **Code Review:** Reviewed p5.js particle physics, Babylon.js camera control, Web Audio API integration
- **Refactoring:** Assisted with modularizing 570-line monolithic file into 14 focused modules
- Extracted scene initialization, camera management, game loop, level generation, collision detection
- Created input handler, material factories, HUD updates, screen manager modules
- Verified no breaking changes, ensured build compatibility, tested audio bundling
- **Documentation:**
### Resources & Documentation
- **Babylon.js Playground:** Reference for collision detection and camera control
- **p5.js Documentation:** Async setup pattern for p5.js 2.0+ (no `preload()`)
- **MDN Web Audio API:** Context priming for cross-browser audio compatibility
- **Babylon.js Playground:** Reference for collision detection, camera control, and mesh creation
---
## Conclusion
**Untitled Maze Game** demonstrates:
- Professional code organization (modular, well-separated concerns)
- Advanced 3D graphics programming (procedural generation, collision detection, camera control)
- Full-featured game loop with state management
- Polish and presentation (particle effects, sound design, responsive UI)
- Scalability (difficulty scaling formula, asset management)
The codebase prioritizes **readability** and **maintainability** through modular design, clear naming conventions, and comprehensive documentation. Each file has a single responsibility, making it easy for collaborators or reviewers to understand and extend the code.
**Untitled Maze Game** was an interesting project as it made me realize that a lot is possible simply through javascript libraries and today's LLMs. AI really saved a lot of time that would have normally taken me hours to debug, and having dialogue with the AI over the code structure and such was quite helpful and interesting. I think the advantage of AI is I can spend a lot more time on thinking about the big-picture structure of the code rather than the little details and line-by-line code, which is more fun.

View File

@@ -33,7 +33,7 @@
</section>
<section class="panel" id="control-panel-section" hidden>
<div class="panel-label">Game Controls</div>
<div class="panel-label">Debug Controls</div>
<div id="control-panel" class="control-panel">
<div class="control-group">
<h3>Run Controls</h3>
@@ -54,6 +54,7 @@
<div class="status-line"><strong>Time left:</strong> <span id="status-time">60.0</span></div>
<div class="status-line"><strong>Key:</strong> <span id="status-key">no</span></div>
<div class="status-line"><strong>Rounds:</strong> <span id="status-rounds">0</span></div>
<div id="status-message" class="status-line-message"></div>
</div>
</div>
</div>

View File

@@ -1,6 +1,8 @@
const initialSeed = Math.floor(Math.random() * 100000);
export const sharedState = (window.mazeGameState ??= {
config: {
seed: Math.floor(Math.random() * 100000),
seed: initialSeed,
level: 1,
mazeWidth: 11,
mazeHeight: 11,
@@ -14,3 +16,6 @@ export const sharedState = (window.mazeGameState ??= {
message: "Press Start to play.",
},
});
// Debug logging
console.log("State initialized with seed:", sharedState.config.seed, "Initial seed value:", initialSeed);

View File

@@ -39,7 +39,6 @@ function updateDisplay() {
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;
}