mirror of
https://github.com/tiennm99/nntv.git
synced 2026-10-16 02:15:39 +00:00
docs: update all project docs for Svelte 5 rewrite and remove old plan
Rewrote project-overview-pdr, system-architecture, code-standards, and codebase-summary to reflect current Svelte 5 architecture, mirror guard mechanic, renderVersion reactivity pattern, and redesigned level progression. Removed obsolete plan/NNTV.md (Phaser 3 plan).
This commit is contained in:
1 parent
0a00209881
commit
40a5b6218f
5 files changed
+462
-809
No files matched your search
+127
-142
@@ -2,17 +2,17 @@
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
### JavaScript Files
|
||||
- **Scenes**: PascalCase (e.g., `Boot.js`, `Game.js`, `MainMenu.js`)
|
||||
- **Classes/Objects**: PascalCase (e.g., `GridSystem.js`, `Player.js`, `Guard.js`)
|
||||
- **Utilities**: camelCase (e.g., `localization.js`, `progress.js`, `theme.js`)
|
||||
### Files
|
||||
- **Svelte components**: PascalCase (`Game.svelte`, `GameBoard.svelte`, `PlayerSprite.svelte`)
|
||||
- **JS modules**: kebab-case (`grid-system.js`, `turn-manager.js`, `level-manager.js`)
|
||||
- **JSON/config**: kebab-case (`en.json`, `vi.json`, `theme.css`)
|
||||
|
||||
### Variables & Functions
|
||||
- **Classes**: PascalCase (`class GridSystem {}`, `class Player {}`)
|
||||
- **Classes**: PascalCase (`GridSystem`, `Player`, `RotatingGuard`)
|
||||
- **Methods & Functions**: camelCase (`updateLight()`, `nextTurn()`, `getText()`)
|
||||
- **Constants**: camelCase in exports (`COLORS`, `FONTS`, `LEVELS`)
|
||||
- **Variables**: camelCase (`playerRow`, `guardColor`, `cellSize`)
|
||||
- **Parameters**: camelCase (`row`, `col`, `guard`)
|
||||
- **Constants**: UPPER_CASE for arrays (`LEVELS`), camelCase for others
|
||||
- **Svelte state**: camelCase (`renderVersion`, `isPaused`, `detected`)
|
||||
- **Props**: camelCase (`cellSize`, `oncellclick`, `onplayagain`)
|
||||
|
||||
### Grid Coordinates
|
||||
- **row**: Vertical axis (0 = top, increases downward)
|
||||
@@ -25,99 +25,111 @@
|
||||
|
||||
```
|
||||
src/
|
||||
├── main.js # Entry point, Phaser config
|
||||
└── game/
|
||||
├── scenes/ # 8 scene files
|
||||
│ ├── Boot.js
|
||||
│ ├── Preloader.js
|
||||
│ ├── MainMenu.js
|
||||
│ ├── StoryIntro.js
|
||||
│ ├── LevelSelect.js
|
||||
│ ├── Game.js # Main gameplay scene
|
||||
│ ├── GameOver.js
|
||||
│ ├── Settings.js
|
||||
│ └── Guide.js
|
||||
├── objects/ # Core game objects
|
||||
│ ├── GridSystem.js
|
||||
│ ├── Player.js
|
||||
│ ├── Guard.js # Base + 4 guard subclasses
|
||||
│ ├── TurnManager.js
|
||||
│ └── LightingSystem.js
|
||||
├── levels/ # Level data & management
|
||||
│ ├── Levels.js # 12 level definitions
|
||||
│ ├── LevelManager.js
|
||||
│ └── LevelTester.js # Debug utility
|
||||
├── locales/ # Localization JSON
|
||||
│ ├── en.json
|
||||
│ └── vi.json
|
||||
├── theme.js # UI constants & factory
|
||||
├── localization.js # String management
|
||||
├── progress.js # Progress persistence
|
||||
└── (additional utilities as needed)
|
||||
├── main.js # Entry point, mounts App.svelte
|
||||
├── App.svelte # Scene router ({#key} + fade)
|
||||
│
|
||||
├── scenes/ # Full-page scene components
|
||||
│ ├── MainMenu.svelte
|
||||
│ ├── StoryIntro.svelte
|
||||
│ ├── LevelIntro.svelte
|
||||
│ ├── LevelSelect.svelte
|
||||
│ ├── Game.svelte # Main gameplay (state owner)
|
||||
│ ├── GameOver.svelte
|
||||
│ ├── Settings.svelte
|
||||
│ └── Guide.svelte
|
||||
│
|
||||
├── components/ # Reusable UI components
|
||||
│ ├── Button.svelte
|
||||
│ ├── GameBoard.svelte # CSS grid rendering
|
||||
│ ├── GameHud.svelte # Level/lives/turns display
|
||||
│ ├── PlayerSprite.svelte # Positioned player div
|
||||
│ ├── GuardSprite.svelte # Colored guard circle/diamond
|
||||
│ ├── PauseMenu.svelte
|
||||
│ └── DetectionPopup.svelte
|
||||
│
|
||||
├── lib/
|
||||
│ ├── game/ # Pure JS game engine (no framework)
|
||||
│ │ ├── grid-system.js
|
||||
│ │ ├── player.js
|
||||
│ │ ├── guards.js # Base + 5 guard subclasses
|
||||
│ │ ├── turn-manager.js
|
||||
│ │ └── level-manager.js
|
||||
│ │
|
||||
│ ├── levels/
|
||||
│ │ └── levels.js # 12 level definitions
|
||||
│ │
|
||||
│ ├── locales/
|
||||
│ │ ├── en.json
|
||||
│ │ └── vi.json
|
||||
│ ├── localization.js
|
||||
│ └── progress.js
|
||||
│
|
||||
└── styles/
|
||||
└── theme.css # CSS variables (colors, fonts)
|
||||
```
|
||||
|
||||
### File Size Limits
|
||||
- **Maximum 200 lines per file** (before considering split)
|
||||
- Scenes with heavy logic → extract objects to `objects/`
|
||||
- Utility functions → consolidate into focused modules
|
||||
- **Maximum 200 lines per file** before considering split
|
||||
- Scenes with heavy logic → extract to `lib/game/`
|
||||
- Shared UI → extract to `components/`
|
||||
|
||||
## Svelte 5 Patterns
|
||||
|
||||
### State Management
|
||||
```javascript
|
||||
// Primitive state
|
||||
let isPaused = $state(false);
|
||||
|
||||
// Class instances (NOT auto-proxied — use renderVersion pattern)
|
||||
let grid = $state(null);
|
||||
let player = $state(null);
|
||||
let renderVersion = $state(0);
|
||||
|
||||
// Derived values depend on renderVersion to pick up class mutations
|
||||
let cells = $derived((renderVersion, grid ? grid.getAllCells() : []));
|
||||
```
|
||||
|
||||
### Props
|
||||
```javascript
|
||||
let { navigate, level = 1, lives = 3 } = $props();
|
||||
```
|
||||
|
||||
### Event Handlers
|
||||
```svelte
|
||||
<!-- Window-level events -->
|
||||
<svelte:window onkeydown={onKeyDown} />
|
||||
|
||||
<!-- Component events via callback props -->
|
||||
<Button text="Resume" onclick={() => isPaused = false} />
|
||||
```
|
||||
|
||||
### Scene Navigation
|
||||
```javascript
|
||||
// Parent passes navigate function as prop
|
||||
navigate('Game', { level: 3, lives: 2 });
|
||||
|
||||
// App.svelte routes via {#key currentScene}
|
||||
```
|
||||
|
||||
## Class & Inheritance Patterns
|
||||
|
||||
### Guard Inheritance Chain
|
||||
### Guard Hierarchy
|
||||
|
||||
```
|
||||
Guard (abstract base)
|
||||
├── StaticGuard
|
||||
├── RotatingGuard
|
||||
├── BlinkingGuard
|
||||
└── PatrollingGuard
|
||||
├── StaticGuard — fixed lit cells
|
||||
├── RotatingGuard — rotating beam + mirror reflection
|
||||
├── BlinkingGuard — toggle on/off
|
||||
├── MirrorGuard — redirects beams
|
||||
└── PatrollingGuard — path movement + directional light
|
||||
```
|
||||
|
||||
**Base Guard Responsibilities:**
|
||||
- Constructor: `scene, grid, row, col, color`
|
||||
- `createSprite()`: Instantiate circle sprite at grid position
|
||||
- `updateLight()`: Overridden by subclasses
|
||||
- `onTurnChange()`: Overridden by subclasses
|
||||
- `destroy()`: Cleanup sprite resources
|
||||
- `update()`: Sync sprite position each frame
|
||||
**Base Guard contract:**
|
||||
- Constructor: `grid, row, col, type`
|
||||
- `updateLight(allGuards?)`: Set lit cells on grid
|
||||
- `onTurnChange(allGuards?)`: Update state then call updateLight
|
||||
|
||||
**Subclass Contract:**
|
||||
- Must implement `updateLight()` → call `grid.setLight()` for lit cells
|
||||
- Must implement `onTurnChange()` → update internal state (rotation, blink, position)
|
||||
- May store additional state (direction, isOn, pathIndex, etc.)
|
||||
|
||||
## Phaser Scene Lifecycle
|
||||
|
||||
All scenes follow standard Phaser pattern:
|
||||
|
||||
```javascript
|
||||
export class ExampleScene extends Phaser.Scene {
|
||||
constructor() {
|
||||
super('SceneName');
|
||||
// Initialize properties only (no heavy setup)
|
||||
}
|
||||
|
||||
init(data) {
|
||||
// Receive data from previous scene
|
||||
}
|
||||
|
||||
preload() {
|
||||
// Load assets (only in Boot & Preloader)
|
||||
}
|
||||
|
||||
create() {
|
||||
// Initialize scene objects, UI, event listeners
|
||||
}
|
||||
|
||||
update() {
|
||||
// Per-frame logic (player input, animations)
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
// Cleanup (optional)
|
||||
}
|
||||
}
|
||||
```
|
||||
**Key rule**: Game engine classes are pure JS with no Svelte dependency. They operate on raw object references, not proxied state.
|
||||
|
||||
## Grid & Coordinate System
|
||||
|
||||
@@ -125,76 +137,49 @@ export class ExampleScene extends Phaser.Scene {
|
||||
- **Row**: 0 = top, increases downward
|
||||
- **Col**: 0 = left, increases rightward
|
||||
- **Cell Data**: `grid[row][col]` = `{ isWall, isGoal, isLight }`
|
||||
- **Screen Coords**: `scene.gridToScreen(row, col)` → `{ x, y }`
|
||||
- **Pixel Position**: `row * cellSize`, `col * cellSize`
|
||||
|
||||
## Theme & UI Constants
|
||||
## Theme & Styling
|
||||
|
||||
**All colors centralized in `theme.js`:**
|
||||
- Grid colors (empty, wall, goal, lit)
|
||||
- Guard colors (static red, rotating blue, blinking yellow, patrolling purple)
|
||||
- UI colors (buttons, text, borders)
|
||||
- Font definitions (title, heading, body, small)
|
||||
All visual constants centralized in `src/styles/theme.css` as CSS variables:
|
||||
- `--bg-dark`, `--bg-panel` — backgrounds
|
||||
- `--grid-empty`, `--grid-wall`, `--grid-goal`, `--grid-lit` — cell colors
|
||||
- `--guard-static`, `--guard-rotating`, `--guard-blinking`, `--guard-patrolling`, `--guard-mirror` — guard colors
|
||||
- `--font-title`, `--font-body`, `--font-button` — typography
|
||||
- `--text-primary`, `--text-accent`, `--text-danger` — text colors
|
||||
|
||||
**Button Creation:**
|
||||
```javascript
|
||||
createButton(scene, x, y, text, onClick, width, height)
|
||||
createSmallButton(scene, x, y, text, onClick)
|
||||
```
|
||||
Component-scoped `<style>` blocks reference these variables. No inline color values.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- **Try-catch**: Used in localStorage operations (`progress.js`, `localization.js`)
|
||||
- **Null checks**: Guard scene objects before method calls (`TurnManager`, `LightingSystem`)
|
||||
- **Validation**: Input bounds checked before grid operations
|
||||
- **Fallback**: Missing translations default to English, then to key itself
|
||||
- **Try-catch**: localStorage operations (`progress.js`, `localization.js`)
|
||||
- **Null checks**: `if (!player || !grid) return` in input handlers
|
||||
- **Validation**: Grid bounds checked before all cell operations
|
||||
- **Fallback**: Missing translations return key string itself
|
||||
|
||||
## Localization Pattern
|
||||
|
||||
```javascript
|
||||
// In any scene:
|
||||
import { getText } from '../localization';
|
||||
import { getText } from '../lib/localization.js';
|
||||
|
||||
const message = getText('level_complete'); // Returns EN or VI string
|
||||
const message = getText('level1Story'); // Returns EN or VI string
|
||||
```
|
||||
|
||||
**Key naming:** `snake_case` matching JSON structure (e.g., `intro_title`, `guard_static`)
|
||||
|
||||
## Performance Guidelines
|
||||
|
||||
- **Grid Rendering**: Single `graphics` object, redraw every frame
|
||||
- **Lighting Calculations**: Batch-compute after all guard actions
|
||||
- **Sprite Updates**: Update position each frame if moving
|
||||
- **Event Listeners**: Register in `create()`, remove in `shutdown()`
|
||||
- **Avoid**: Nested loops for 10x10 grids acceptable; limit nested loops for 8+ guards
|
||||
Key naming: camelCase matching JSON structure (`levelSelectTitle`, `enemyTypesContent`).
|
||||
|
||||
## Git & Commit Conventions
|
||||
|
||||
- **Commits**: Follow conventional commits (feat, fix, refactor, test, docs)
|
||||
- **Branch**: `main` for production, feature branches for development
|
||||
- **Messages**: Descriptive, reference issue numbers when applicable
|
||||
- **Example**: `feat: add rotating guard AI type`
|
||||
|
||||
## Testing
|
||||
|
||||
- **Unit Tests**: Test guard AI logic, grid validation, level loading
|
||||
- **Integration Tests**: Test turn cycles, detection mechanics
|
||||
- **Manual QA**: Play all 12 levels, verify UI responsiveness
|
||||
- **Browser**: Test on Chrome, Firefox, Safari (Phaser AUTO handles rendering)
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
- **Comments**: Explain "why" not "what"; code clarity preferred over comments
|
||||
- **Complex Logic**: Comment guard AI decision logic, collision detection
|
||||
- **Localization**: Document new translation keys in locale JSON files
|
||||
- **Breaking Changes**: Note in commit message and update related docs
|
||||
- **Format**: Conventional commits (`feat:`, `fix:`, `refactor:`, `test:`, `docs:`)
|
||||
- **Branch**: `main` for production
|
||||
- **Messages**: Descriptive, explain "why" not just "what"
|
||||
- **Example**: `fix: resolve Svelte 5 reactivity for class instances`
|
||||
|
||||
## Code Review Checklist
|
||||
|
||||
- [ ] Follows naming conventions (PascalCase classes, camelCase methods)
|
||||
- [ ] Follows naming conventions (PascalCase components, kebab-case JS modules)
|
||||
- [ ] No dead code or commented-out blocks
|
||||
- [ ] Error handling for async/localStorage operations
|
||||
- [ ] Null/undefined checks for dynamic objects
|
||||
- [ ] Consistent indentation (2 spaces per Phaser convention)
|
||||
- [ ] No hardcoded colors (use `theme.js` COLORS)
|
||||
- [ ] Localization keys used instead of hardcoded strings
|
||||
- [ ] File size under 200 lines (split if needed)
|
||||
- [ ] Class mutations followed by `renderVersion++`
|
||||
- [ ] No hardcoded colors (use CSS variables)
|
||||
- [ ] Localization keys used for all user-facing strings
|
||||
- [ ] File size under 200 lines
|
||||
- [ ] Pure JS game logic has no Svelte imports
|
||||
+125
-216
@@ -2,281 +2,190 @@
|
||||
|
||||
## Overview
|
||||
|
||||
NNTV is a turn-based stealth puzzle game built with Phaser 3.88.2 and Vite 6.3.6. The codebase is organized into reusable modules with clear separation of concerns: scenes manage UI/flow, game objects handle logic, and utilities provide cross-cutting functionality.
|
||||
|
||||
**Total Files:** 21 JavaScript modules + 2 JSON locale files + config files
|
||||
NNTV is a turn-based stealth puzzle game built with Svelte 5 and Vite 6.x. The codebase separates pure JS game engine (classes in `lib/game/`) from Svelte rendering (scenes + components). State flows one-way: game classes mutate internally, then `renderVersion++` triggers Svelte re-derivation.
|
||||
|
||||
## Module Inventory
|
||||
|
||||
### Entry Point
|
||||
- **src/main.js** (35 lines)
|
||||
- Phaser game initialization
|
||||
- Scene registration (8 scenes in order)
|
||||
- Canvas size: 1024x768, scale mode FIT
|
||||
- Arcade physics disabled (grid-based movement only)
|
||||
- **src/main.js** — Mounts `App.svelte` into `#app`
|
||||
|
||||
### Game Scenes (src/game/scenes/)
|
||||
### Scene Router
|
||||
- **src/App.svelte** — `{#key currentScene}` with `transition:fade`, passes `navigate` function as prop to all scenes
|
||||
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| Boot.js | ~40 | System initialization |
|
||||
| Preloader.js | ~60 | Asset loading (sprites, audio) |
|
||||
| MainMenu.js | ~100 | Start game, settings, guide buttons |
|
||||
| StoryIntro.js | ~50 | Opening narrative sequence |
|
||||
| LevelSelect.js | ~120 | Level list, progress display, level launch |
|
||||
| Game.js | ~300 | Main gameplay loop, UI, input handling |
|
||||
| GameOver.js | ~80 | Loss screen, retry/menu options |
|
||||
| Settings.js | ~70 | Language toggle, preferences |
|
||||
| Guide.js | ~90 | Instructions, controls, gameplay rules |
|
||||
### Scenes (src/scenes/)
|
||||
|
||||
### Core Game Objects (src/game/objects/)
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| MainMenu.svelte | Start game, level select, settings, guide |
|
||||
| StoryIntro.svelte | Scrolling narrative with skip button |
|
||||
| LevelIntro.svelte | Level name + story text + continue |
|
||||
| LevelSelect.svelte | 4x3 grid of level buttons (locked/unlocked/completed) |
|
||||
| Game.svelte | Main gameplay: state owner, input, turn loop, rendering |
|
||||
| GameOver.svelte | Loss/twist screen, retry/menu |
|
||||
| Settings.svelte | Language toggle (EN/VI) |
|
||||
| Guide.svelte | Rules, controls, enemy types |
|
||||
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| GridSystem.js | ~100 | Grid state management, cell queries, rendering |
|
||||
| Player.js | ~80 | Ninja rabbit logic, movement, detection |
|
||||
| Guard.js | ~150 | Base Guard class + 4 subclasses (Static, Rotating, Blinking, Patrolling) |
|
||||
| TurnManager.js | ~60 | Turn cycle execution, detection checks |
|
||||
| LightingSystem.js | ~50 | Light aggregation from guards, rendering |
|
||||
### Components (src/components/)
|
||||
|
||||
### Level Management (src/game/levels/)
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| Button.svelte | Reusable styled button |
|
||||
| GameBoard.svelte | CSS grid rendering of cells |
|
||||
| GameHud.svelte | Level, lives, turns display bar |
|
||||
| PlayerSprite.svelte | Absolutely positioned player div |
|
||||
| GuardSprite.svelte | Colored circle (or diamond for mirror) |
|
||||
| DetectionPopup.svelte | "Detected!" overlay with retry |
|
||||
| PauseMenu.svelte | Resume / restart / main menu |
|
||||
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| Levels.js | ~450 | 12 level definitions (grid size, guards, walls, goals) |
|
||||
| LevelManager.js | ~60 | Load/initialize level by ID |
|
||||
| LevelTester.js | ~80 | Debug utility for testing levels |
|
||||
### Game Engine (src/lib/game/) — Pure JS, no Svelte
|
||||
|
||||
### Utilities & Configuration (src/game/)
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| grid-system.js | GridSystem class: cell state, walls, goals, lighting |
|
||||
| player.js | Player class: position, movement validation |
|
||||
| guards.js | Guard base + 5 subclasses (Static, Rotating, Blinking, Mirror, Patrolling) |
|
||||
| turn-manager.js | TurnManager: turn cycle, guard updates, detection |
|
||||
| level-manager.js | loadLevel(): instantiate grid, player, guards from level data |
|
||||
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| theme.js | ~71 | COLORS, FONTS constants; button factory functions |
|
||||
| localization.js | ~60 | Multi-language string management (EN/VI) |
|
||||
| progress.js | ~43 | Level completion tracking via localStorage |
|
||||
### Level Data (src/lib/levels/)
|
||||
|
||||
### Localization (src/game/locales/)
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| levels.js | LEVELS array: 12 level definitions (grid, guards, walls, goals) |
|
||||
|
||||
### Utilities (src/lib/)
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| localization.js | getText/setLanguage/getLanguage/initLanguage |
|
||||
| progress.js | getProgress/completeLevel via localStorage |
|
||||
|
||||
### Localization (src/lib/locales/)
|
||||
|
||||
| File | Keys | Purpose |
|
||||
|------|------|---------|
|
||||
| en.json | ~50 | English translations (titles, buttons, messages) |
|
||||
| vi.json | ~50 | Vietnamese translations (parallel structure) |
|
||||
| en.json | ~55 | English translations |
|
||||
| vi.json | ~55 | Vietnamese translations |
|
||||
|
||||
### Styles (src/styles/)
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| theme.css | CSS variables: colors, fonts, guard colors, grid colors |
|
||||
|
||||
## Class Hierarchy
|
||||
|
||||
### Guard Inheritance
|
||||
|
||||
```
|
||||
Guard (abstract)
|
||||
├─ StaticGuard (always light same cells)
|
||||
├─ RotatingGuard (rotate direction 90° per turn)
|
||||
├─ BlinkingGuard (toggle lights on/off)
|
||||
└─ PatrollingGuard (move on path, light adjacent)
|
||||
```
|
||||
|
||||
All guards share:
|
||||
- Constructor params: `scene, grid, row, col, color`
|
||||
- Methods: `createSprite()`, `destroy()`, `update()`
|
||||
- Abstract methods (subclass override): `updateLight()`, `onTurnChange()`
|
||||
- Sprite: Phaser circle object (colored by type)
|
||||
|
||||
### Scene Inheritance
|
||||
|
||||
All inherit from `Phaser.Scene`:
|
||||
```
|
||||
Phaser.Scene
|
||||
├─ Boot (init phase)
|
||||
├─ Preloader (asset loading)
|
||||
├─ MainMenu (UI hub)
|
||||
├─ StoryIntro (narrative)
|
||||
├─ LevelSelect (level navigation)
|
||||
├─ Game (gameplay)
|
||||
├─ GameOver (loss/retry)
|
||||
├─ Settings (preferences)
|
||||
└─ Guide (help)
|
||||
Guard (abstract base: grid, row, col, type, direction, isOn)
|
||||
├── StaticGuard — lights fixed litCells array
|
||||
├── RotatingGuard — rotates beam 90°/turn, castBeam with mirror bounce
|
||||
├── BlinkingGuard — toggles isOn, lights litCells when on
|
||||
├── MirrorGuard — lights own cell, stores reflectDirection (cw/ccw)
|
||||
└── PatrollingGuard — follows path array, lights front + right cells
|
||||
```
|
||||
|
||||
## Key Data Structures
|
||||
|
||||
### Level Object
|
||||
### Level Definition
|
||||
```javascript
|
||||
{
|
||||
id: 1, // 1-12
|
||||
name: "First Steps",
|
||||
id: 1, name: "Garden Path", storyKey: "level1Story",
|
||||
grid: { rows: 6, cols: 6 },
|
||||
player: { row: 0, col: 0 },
|
||||
goal: { row: 5, col: 5 },
|
||||
walls: [{ row: 1, col: 1 }, ...],
|
||||
guards: [
|
||||
{ type: "static", position: {...}, litCells: [...] },
|
||||
{ type: "rotating", position: {...}, direction: 0 },
|
||||
...
|
||||
]
|
||||
{ type: "static", position: { row: 2, col: 4 }, litCells: [...] },
|
||||
{ type: "rotating", position: { row: 3, col: 3 }, startDirection: 0 },
|
||||
{ type: "blinking", position: {...}, litCells: [...], startState: true },
|
||||
{ type: "mirror", position: {...}, reflectDirection: "cw" },
|
||||
{ type: "patrolling", startPosition: {...}, path: [...] },
|
||||
],
|
||||
isFinalLevel: false
|
||||
}
|
||||
```
|
||||
|
||||
### Cell State
|
||||
```javascript
|
||||
{
|
||||
isWall: boolean,
|
||||
isGoal: boolean,
|
||||
isLight: boolean
|
||||
}
|
||||
{ isWall: boolean, isGoal: boolean, isLight: boolean }
|
||||
```
|
||||
|
||||
### Progress Object
|
||||
### Progress (localStorage)
|
||||
```javascript
|
||||
{
|
||||
maxLevel: 1, // Highest unlocked level
|
||||
completedLevels: [1, 2, 3] // Array of completed level IDs
|
||||
}
|
||||
{ maxLevel: 1, completedLevels: [1, 2, 3] }
|
||||
```
|
||||
|
||||
## Public API Summary
|
||||
|
||||
### GridSystem
|
||||
```
|
||||
new GridSystem(rows, cols, cellSize)
|
||||
.isValidPosition(row, col), .isWall(row, col), .setWall(row, col, value)
|
||||
.isGoal(row, col), .setGoal(row, col, value)
|
||||
.isLight(row, col), .setLight(row, col, value)
|
||||
.clearAllLight(), .getAllCells() → [{row, col, isWall, isGoal, isLight}]
|
||||
```
|
||||
|
||||
### Player
|
||||
```
|
||||
new Player(grid, row, col)
|
||||
.move(direction) → boolean, .moveTo(row, col) → boolean
|
||||
.isInLitCell() → boolean, .isAtGoal() → boolean
|
||||
```
|
||||
|
||||
### Guards
|
||||
```
|
||||
All: .updateLight(allGuards?), .onTurnChange(allGuards?)
|
||||
RotatingGuard: .castBeam(dir, fromRow, fromCol, range, allGuards, depth)
|
||||
PatrollingGuard: .checkIfCircularPath(), path traversal with reversing
|
||||
MirrorGuard: .reflectDirection ('cw' or 'ccw')
|
||||
```
|
||||
|
||||
### TurnManager
|
||||
```
|
||||
new TurnManager()
|
||||
.nextTurn(grid, player, guards) → { detected, levelComplete }
|
||||
.reset()
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| phaser | 3.88.2 | Game framework (rendering, physics, input) |
|
||||
| svelte | 5.x | UI framework (runes mode) |
|
||||
| vite | 6.3.6 | Build tool, dev server |
|
||||
| terser | 5.39.0 | JS minification (prod build) |
|
||||
|
||||
## Public API Summary
|
||||
|
||||
### GridSystem
|
||||
```javascript
|
||||
new GridSystem(scene, rows, cols, cellSize)
|
||||
.isValidPosition(row, col) → boolean
|
||||
.isWall(row, col) → boolean
|
||||
.setWall(row, col, value)
|
||||
.isGoal(row, col) → boolean
|
||||
.setGoal(row, col, value)
|
||||
.isLight(row, col) → boolean
|
||||
.setLight(row, col, value)
|
||||
.render(offsetX, offsetY, cellSize)
|
||||
```
|
||||
|
||||
### Player
|
||||
```javascript
|
||||
new Player(scene, grid, row, col)
|
||||
.move(newRow, newCol) → boolean
|
||||
.update()
|
||||
.destroy()
|
||||
```
|
||||
|
||||
### Guard (Base)
|
||||
```javascript
|
||||
new Guard(scene, grid, row, col, color)
|
||||
.createSprite()
|
||||
.updateLight() // Override in subclass
|
||||
.onTurnChange() // Override in subclass
|
||||
.destroy()
|
||||
.update()
|
||||
```
|
||||
|
||||
### TurnManager
|
||||
```javascript
|
||||
new TurnManager(scene)
|
||||
.nextTurn() // Execute guard actions, detect collision
|
||||
.reset()
|
||||
```
|
||||
|
||||
### LightingSystem
|
||||
```javascript
|
||||
new LightingSystem(scene, grid)
|
||||
.clearAllLight()
|
||||
.updateLightFromGuards(guards)
|
||||
```
|
||||
|
||||
### Localization
|
||||
```javascript
|
||||
getText(key) → string // Get current language text
|
||||
setLanguage(lang) → boolean // 'en' or 'vi'
|
||||
getLanguage() → string
|
||||
initLanguage() // Load from localStorage
|
||||
```
|
||||
|
||||
### Progress
|
||||
```javascript
|
||||
getProgress() → { maxLevel, completedLevels }
|
||||
completeLevel(levelNum, totalLevels) → updated progress
|
||||
```
|
||||
| @sveltejs/vite-plugin-svelte | 6.x | Svelte compiler for Vite |
|
||||
|
||||
## File Dependency Map
|
||||
|
||||
```
|
||||
main.js
|
||||
└─ Boot, Preloader, MainMenu, StoryIntro, LevelSelect, Game, GameOver, Settings, Guide
|
||||
main.js → App.svelte
|
||||
App.svelte → all scenes
|
||||
|
||||
Game.js
|
||||
├─ GridSystem
|
||||
├─ Player
|
||||
├─ Guard (+ 4 subclasses)
|
||||
├─ TurnManager
|
||||
├─ LightingSystem
|
||||
├─ LevelManager → Levels
|
||||
├─ localization
|
||||
├─ theme
|
||||
└─ progress
|
||||
Game.svelte (central hub)
|
||||
├── lib/game/level-manager.js → grid-system, player, guards, levels
|
||||
├── lib/game/turn-manager.js
|
||||
├── lib/progress.js
|
||||
├── lib/localization.js
|
||||
├── components/GameBoard, PlayerSprite, GuardSprite, GameHud
|
||||
├── components/DetectionPopup, PauseMenu
|
||||
└── renderVersion pattern for reactivity
|
||||
|
||||
LevelManager.js
|
||||
└─ Levels
|
||||
|
||||
LevelSelect.js
|
||||
├─ LevelManager
|
||||
├─ progress
|
||||
├─ localization
|
||||
└─ theme
|
||||
|
||||
All Scenes
|
||||
├─ localization (for UI text)
|
||||
├─ theme (for colors, fonts, buttons)
|
||||
└─ progress (for tracking)
|
||||
LevelSelect.svelte → levels.js, progress.js, localization.js
|
||||
LevelIntro.svelte → levels.js, localization.js
|
||||
All scenes → localization.js (for UI text)
|
||||
```
|
||||
|
||||
## Configuration Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| vite/config.dev.mjs | Dev server config (hot reload, logging) |
|
||||
| vite/config.prod.mjs | Prod build config (minify, optimize) |
|
||||
| index.html | Entry HTML, Phaser div target (#app) |
|
||||
| public/style.css | Global styles (layout, responsive) |
|
||||
| package.json | Dependencies, npm scripts |
|
||||
|
||||
## Asset Organization
|
||||
|
||||
- **public/assets/**: Static sprites, audio, images (served directly)
|
||||
- **Imported in Preloader.js**: Load via Phaser loader
|
||||
- **Vite bundling**: ES module imports for bundled assets
|
||||
|
||||
## Build Output
|
||||
|
||||
**Dev Mode:** `npm run dev`
|
||||
- Source maps enabled
|
||||
- Hot module reload
|
||||
- Dev logging active
|
||||
|
||||
**Prod Mode:** `npm run build`
|
||||
- Minified JS (terser)
|
||||
- Assets optimized
|
||||
- Output to `dist/` directory
|
||||
|
||||
## Statistics
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total JS Lines | ~2,100 |
|
||||
| Number of Classes | 12 (8 scenes + 4 objects) |
|
||||
| Number of Levels | 12 |
|
||||
| Localization Keys | ~50 |
|
||||
| Total Source Files | ~20 (8 scenes + 7 components + 5 engine + utils) |
|
||||
| Number of Classes | 7 (GridSystem, Player, Guard + 5 subclasses, TurnManager) |
|
||||
| Number of Levels | 12 (across 6 acts) |
|
||||
| Guard Types | 5 (Static, Rotating, Blinking, Mirror, Patrolling) |
|
||||
| Localization Keys | ~55 per language |
|
||||
| Max Grid Size | 10x10 |
|
||||
| Max Guards/Level | 8 |
|
||||
| Browser Support | All (Phaser AUTO) |
|
||||
|
||||
## Code Quality Notes
|
||||
|
||||
- **No external frameworks** beyond Phaser (pure vanilla JS + ES modules)
|
||||
- **Consistent patterns**: Guard inheritance, scene lifecycle, utility exports
|
||||
- **Error handling**: Try-catch in localStorage, null checks for dynamic objects
|
||||
- **Localization**: Full coverage EN/VI, fallback to English
|
||||
- **Performance**: Synchronous turn system, optimized lighting calculations
|
||||
@@ -5,10 +5,11 @@
|
||||
**Night Ninja: Twilight Voyage (NNTV)** is a turn-based stealth puzzle browser game where players control a ninja rabbit navigating grid-based levels to rescue the Carrot Princess from the Vegetable Kingdom.
|
||||
|
||||
### Core Concept
|
||||
- Turn-based grid movement with real-time lighting detection
|
||||
- Multiple guard AI types with distinct behaviors
|
||||
- Progressive difficulty across 12 levels
|
||||
- Turn-based grid movement with lighting-based detection
|
||||
- 5 guard AI types with distinct behaviors
|
||||
- Progressive difficulty across 12 levels in 6 acts
|
||||
- Bilingual support (English/Vietnamese)
|
||||
- Narrative twist ending with escalating detection mechanic
|
||||
|
||||
### Target Audience
|
||||
- Casual puzzle game players (10+)
|
||||
@@ -17,8 +18,8 @@
|
||||
|
||||
### Platform
|
||||
- Web browser (desktop, responsive)
|
||||
- Technology: Phaser 3.88.2 + Vite 6.3.6
|
||||
- Languages: Vanilla JavaScript (ES modules)
|
||||
- Technology: Svelte 5 + Vite 6.x
|
||||
- Languages: JavaScript (ES modules) + Svelte components
|
||||
|
||||
## Product Development Requirements
|
||||
|
||||
@@ -26,69 +27,88 @@
|
||||
|
||||
| Requirement | Description | Status |
|
||||
|---|---|---|
|
||||
| Grid-based Movement | Player moves one cell per turn via arrow keys or mouse click | Complete |
|
||||
| Guard AI System | Four distinct guard types (Static, Rotating, Blinking, Patrolling) | Complete |
|
||||
| Grid-based Movement | Player moves one cell per turn via arrow keys, WASD, or cell click | Complete |
|
||||
| Guard AI System | 5 guard types (Static, Rotating, Blinking, Patrolling, Mirror) | Complete |
|
||||
| Mirror Reflection | Rotating guard beams bounce off mirror guards at 90 degrees | Complete |
|
||||
| Detection System | Players lose a life when stepping on lit cells | Complete |
|
||||
| Level Progression | 12 difficulty-scaled levels with persistent progress tracking | Complete |
|
||||
| Win Condition | Reach goal cell to advance; complete all 12 levels to win | Complete |
|
||||
| Level Progression | 12 difficulty-scaled levels with localStorage progress tracking | Complete |
|
||||
| Win Condition | Reach goal cell to advance; level 12 is unbeatable (narrative twist) | Complete |
|
||||
| Lives System | 3 lives per play session; game over at zero lives | Complete |
|
||||
| Escalating Detection | Level 12: light radiates outward from princess when player approaches | Complete |
|
||||
|
||||
### Non-Functional Requirements
|
||||
|
||||
| Requirement | Description | Status |
|
||||
|---|---|---|
|
||||
| Localization | English and Vietnamese via localStorage persistence | Complete |
|
||||
| UI/UX Consistency | Centralized theme (colors, fonts, button styles) | Complete |
|
||||
| Asset Management | Vite module imports for sprites and static assets | Complete |
|
||||
| Performance | 60 FPS gameplay on modern browsers (Phaser default) | Complete |
|
||||
| Browser Support | Phaser AUTO type (Canvas/WebGL auto-detection) | Complete |
|
||||
| UI/UX Consistency | CSS variables theme (colors, fonts, button styles) | Complete |
|
||||
| Svelte 5 Reactivity | renderVersion counter pattern for class instance mutations | Complete |
|
||||
| Performance | Lightweight Svelte 5 rendering, no heavy framework overhead | Complete |
|
||||
| Browser Support | Modern browsers with ES module support | Complete |
|
||||
|
||||
### User Interface Components
|
||||
|
||||
- **Main Menu**: Start game, settings, guide
|
||||
- **Level Select**: View unlocked levels, track progress
|
||||
- **Main Menu**: Start game, level select, settings, guide
|
||||
- **Story Intro**: Scrolling narrative with skip option
|
||||
- **Level Intro**: Level name, story text, continue button
|
||||
- **Level Select**: Grid of level buttons with lock/complete states
|
||||
- **Game HUD**: Current level, lives remaining, turn count
|
||||
- **Game Board**: Grid cells rendered via Svelte component
|
||||
- **Settings Panel**: Language toggle (EN/VI)
|
||||
- **Guide/Instructions**: Game rules and controls
|
||||
- **Game Over Screen**: Retry level or return to menu
|
||||
- **Guide**: Game rules, controls, enemy types
|
||||
- **Detection Popup**: Retry prompt on detection
|
||||
- **Pause Menu**: Resume, restart, main menu
|
||||
- **Game Over Screen**: Retry or return to menu
|
||||
|
||||
### Game Mechanics
|
||||
|
||||
**Turn Cycle:**
|
||||
1. Player executes move (arrow keys/mouse)
|
||||
2. Grid updates player position
|
||||
1. Player executes move (arrow keys / WASD / cell click)
|
||||
2. Player position updates (validated against walls/bounds)
|
||||
3. Guards execute turn actions (rotate, blink, patrol)
|
||||
4. Lighting system recalculates lit cells
|
||||
5. Detection check: if player on lit cell, lose life + restart level
|
||||
6. Advance to goal: level complete, unlock next level
|
||||
6. Goal check (before guard update): level complete, unlock next
|
||||
|
||||
**Guard Behaviors:**
|
||||
- **Static**: Lights fixed adjacent cells every turn
|
||||
- **Rotating**: Rotates light direction 90° each turn
|
||||
- **Blinking**: Toggles lights on/off each turn
|
||||
- **Patrolling**: Moves along predefined path, lights adjacent cells
|
||||
- **Level 12 Special**: Princess detection at distance 2, full map illuminate
|
||||
- **Static (red)**: Lights fixed adjacent cells every turn
|
||||
- **Rotating (blue)**: Rotates light direction 90 degrees each turn, casts beam of 2 cells
|
||||
- **Blinking (yellow)**: Toggles lights on/off each turn
|
||||
- **Patrolling (purple)**: Moves along predefined path, lights front + right cells
|
||||
- **Mirror (green)**: Redirects rotating guard beams 90 degrees (cw or ccw)
|
||||
- **Level 12 Special**: Princess detection — light radiates from goal at distance 4, expanding 1 ring per turn
|
||||
|
||||
### Level Progression (6 Acts)
|
||||
|
||||
| Act | Levels | Focus |
|
||||
|-----|--------|-------|
|
||||
| 1: Outskirts | 1-2 | Movement basics + static guards |
|
||||
| 2: Garden | 3-4 | Walls as shields + rotating guards |
|
||||
| 3: Fortress | 5-6 | Blinking guards + timing puzzles |
|
||||
| 4: Underground | 7-8 | Patrolling guards + path prediction |
|
||||
| 5: Palace | 9-11 | Combinations, decoy paths, mirror guards |
|
||||
| 6: Chamber | 12 | Narrative twist with escalating detection |
|
||||
|
||||
### Success Metrics
|
||||
|
||||
- All 12 levels completable without game crashes
|
||||
- All 11 levels completable without game crashes (level 12 is intentionally unbeatable)
|
||||
- Turn-based mechanics execute without delay
|
||||
- No memory leaks during 30+ minute gameplay sessions
|
||||
- UI responsive to all input methods (keyboard, mouse, touch)
|
||||
- Localization string coverage >= 95%
|
||||
- No memory leaks during extended gameplay sessions
|
||||
- UI responsive to all input methods (keyboard, mouse)
|
||||
- Localization string coverage 100%
|
||||
|
||||
### Technical Constraints
|
||||
|
||||
- Vanilla JavaScript only (no frameworks beyond Phaser)
|
||||
- Grid size capped at 10x10 for performance
|
||||
- Max 8 guards per level (lighting system performance)
|
||||
- Phaser 3.x compatibility required
|
||||
- ES modules only (no CommonJS)
|
||||
- Svelte 5 runes mode (`$state`, `$derived`, `$props`)
|
||||
- Class instances require `renderVersion` pattern for reactivity
|
||||
- Grid size capped at 10x10
|
||||
- Max 8 guards per level
|
||||
- ES modules only
|
||||
|
||||
## Project Status
|
||||
|
||||
**Current Version:** 0.0.1
|
||||
**Repository:** GitHub (private)
|
||||
**Current Version:** 0.1.0
|
||||
**Repository:** GitHub
|
||||
**Last Updated:** 2026-04-12
|
||||
|
||||
All core gameplay features implemented and functional. Project ready for content expansion and quality assurance testing.
|
||||
All core gameplay features implemented. Svelte 5 rewrite complete with reactivity fix, mirror guard mechanic, redesigned level progression, and escalating final level twist.
|
||||
+153
-125
@@ -4,163 +4,191 @@
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Phaser Game Instance │
|
||||
│ Config: 1024x768, Scale.FIT, Arcade Physics (disabled) │
|
||||
│ Svelte 5 Application │
|
||||
│ Entry: src/main.js → mounts App.svelte into #app │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────┴──────────────────┐
|
||||
↓ ↓
|
||||
┌─────────────────┐ ┌──────────────────────┐
|
||||
│ Scene Manager │ │ Game Scenes │
|
||||
└─────────────────┘ ├──────────────────────┤
|
||||
│ Boot │
|
||||
│ Preloader │
|
||||
│ MainMenu │
|
||||
│ StoryIntro │
|
||||
│ LevelSelect │
|
||||
│ Game (main gameplay) │
|
||||
│ GameOver │
|
||||
│ Settings │
|
||||
│ Guide │
|
||||
│ Scene Router │ │ Scenes (Svelte) │
|
||||
│ App.svelte │ ├──────────────────────┤
|
||||
│ {#key} block │ │ MainMenu.svelte │
|
||||
│ + fade trans. │ │ StoryIntro.svelte │
|
||||
└─────────────────┘ │ LevelIntro.svelte │
|
||||
│ LevelSelect.svelte │
|
||||
│ Game.svelte (gameplay) │
|
||||
│ GameOver.svelte │
|
||||
│ Settings.svelte │
|
||||
│ Guide.svelte │
|
||||
└──────────────────────┘
|
||||
┌──────────────────────────────────────┐
|
||||
│ Pure JS Game Engine (no framework) │
|
||||
├──────────────────────────────────────┤
|
||||
│ GridSystem │ Player │ Guards │
|
||||
│ TurnManager │ Levels │ Progress │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Scene Flow
|
||||
|
||||
```
|
||||
Boot
|
||||
↓
|
||||
Preloader (load assets)
|
||||
↓
|
||||
MainMenu (user selects start/settings/guide)
|
||||
MainMenu
|
||||
├→ Settings (toggle language) → MainMenu
|
||||
├→ Guide (view instructions) → MainMenu
|
||||
└→ StoryIntro (intro sequence)
|
||||
↓
|
||||
LevelSelect (view unlocked levels, select level)
|
||||
↓
|
||||
Game (turn-based gameplay)
|
||||
├→ Level Complete → LevelSelect (or next level)
|
||||
└→ Game Over (3 lives lost)
|
||||
↓
|
||||
GameOver Scene (retry/menu)
|
||||
├→ LevelSelect → LevelIntro → Game
|
||||
└→ StoryIntro → LevelIntro → Game
|
||||
|
||||
Game (turn-based gameplay loop)
|
||||
├→ Level Complete → LevelIntro (next level)
|
||||
├→ Detection (lives > 0) → restart same level
|
||||
└→ Game Over (0 lives or final level)
|
||||
└→ GameOver → MainMenu
|
||||
```
|
||||
|
||||
Navigation is handled by `App.svelte` via a `navigate(scene, data)` function passed as prop. Scene switching uses `{#key currentScene}` with `transition:fade`.
|
||||
|
||||
## Core Game Objects Architecture
|
||||
|
||||
```
|
||||
Game Scene
|
||||
├── GridSystem
|
||||
│ ├── Grid Data: Array[rows][cols] with cell states
|
||||
│ ├── Methods: isValidPosition, setWall, isGoal, isLight, etc.
|
||||
│ └── Graphics: Renders grid borders, walls, goal, lighting
|
||||
Game.svelte (state owner, input handler, render coordinator)
|
||||
├── GridSystem (pure JS class)
|
||||
│ ├── Grid Data: Array[rows][cols] → { isWall, isGoal, isLight }
|
||||
│ ├── Methods: isValidPosition, setWall, isGoal, isLight, setLight
|
||||
│ ├── clearAllLight(): Reset all cells before guard turn
|
||||
│ └── getAllCells(): Flat array for Svelte rendering
|
||||
│
|
||||
├── Player
|
||||
│ ├── State: row, col, alive flag
|
||||
│ ├── Methods: move(row,col), detectLighting(), update()
|
||||
│ └── Sprite: Ninja rabbit circle (black)
|
||||
├── Player (pure JS class)
|
||||
│ ├── State: row, col, grid reference
|
||||
│ ├── move(direction): Validates bounds + walls, updates position
|
||||
│ ├── isInLitCell(): Detection check
|
||||
│ └── isAtGoal(): Win condition check
|
||||
│
|
||||
├── Guards[] (dynamic array)
|
||||
│ ├── Base Class: Guard
|
||||
│ │ ├── Shared: sprite, row, col, color, createSprite()
|
||||
├── Guards[] (pure JS class hierarchy)
|
||||
│ ├── Guard (abstract base)
|
||||
│ │ ├── Shared: grid, row, col, type, direction, isOn
|
||||
│ │ └── Abstract: updateLight(), onTurnChange()
|
||||
│ │
|
||||
│ ├── StaticGuard extends Guard
|
||||
│ │ ├── Lights: Fixed set of adjacent cells
|
||||
│ │ └── Sprite Color: Red (#ff4444)
|
||||
│ │
|
||||
│ ├── RotatingGuard extends Guard
|
||||
│ │ ├── Lights: 2 cells ahead in rotating direction
|
||||
│ │ ├── Rotation: 90° clockwise each turn
|
||||
│ │ └── Sprite Color: Blue (#4488ff)
|
||||
│ │
|
||||
│ ├── BlinkingGuard extends Guard
|
||||
│ │ ├── Lights: Toggle on/off every turn
|
||||
│ │ ├── State: isOn flag tracking
|
||||
│ │ └── Sprite Color: Yellow (#ffdd44) / Dark yellow (#887722)
|
||||
│ │
|
||||
│ └── PatrollingGuard extends Guard
|
||||
│ ├── Lights: Front + right cells
|
||||
│ ├── Movement: Predefined path array
|
||||
│ └── Sprite Color: Purple (#bb44ff)
|
||||
│ ├── StaticGuard — lights fixed adjacent cells
|
||||
│ ├── RotatingGuard — rotates beam 90°/turn, reflects off mirrors
|
||||
│ ├── BlinkingGuard — toggles lights on/off each turn
|
||||
│ ├── MirrorGuard — redirects rotating beams (cw/ccw 90°)
|
||||
│ └── PatrollingGuard — follows path, lights front + right
|
||||
│
|
||||
├── TurnManager
|
||||
│ ├── State: isPlayerTurn, turnCount
|
||||
│ ├── nextTurn(): Execute guard actions, detect collision
|
||||
│ └── Cycle: Player move → Guards update → Detection check
|
||||
├── TurnManager (pure JS class)
|
||||
│ ├── turnCount tracking
|
||||
│ └── nextTurn(): clear lights → update guards → detect
|
||||
│
|
||||
├── LightingSystem
|
||||
│ ├── Graphics: Overlay layer for lit cell visualization
|
||||
│ ├── updateLightFromGuards(): Aggregate all guard lights
|
||||
│ └── clearAllLight(): Reset before each guard turn
|
||||
│
|
||||
└── LevelManager
|
||||
├── Levels.js: Level data (grid, guards, walls, goal)
|
||||
├── loadLevel(num): Instantiate level configuration
|
||||
└── 12 predefined levels with progressive difficulty
|
||||
└── Svelte Components (rendering only)
|
||||
├── GameBoard.svelte — CSS grid of cells
|
||||
├── PlayerSprite.svelte — positioned div
|
||||
├── GuardSprite.svelte — colored circle/diamond
|
||||
├── GameHud.svelte — level, lives, turns display
|
||||
├── DetectionPopup.svelte — retry prompt
|
||||
└── PauseMenu.svelte — resume/restart/menu
|
||||
```
|
||||
|
||||
## Svelte 5 Reactivity Pattern
|
||||
|
||||
**Problem**: Svelte 5 does not deep-proxy class instances. Mutations inside `Player.move()` or `Guard.onTurnChange()` are invisible to the reactivity system. Self-assignment (`grid = grid`) is a no-op due to `===` equality check.
|
||||
|
||||
**Solution**: `renderVersion` counter pattern.
|
||||
|
||||
```javascript
|
||||
let renderVersion = $state(0);
|
||||
|
||||
// Derived values depend on renderVersion via comma operator
|
||||
let cells = $derived((renderVersion, grid ? grid.getAllCells() : []));
|
||||
let playerRow = $derived((renderVersion, player ? player.row : 0));
|
||||
let guardSnapshots = $derived((renderVersion, guards.map(g => ({
|
||||
row: g.row, col: g.col, type: g.type, direction: g.direction, isOn: g.isOn
|
||||
}))));
|
||||
|
||||
// After any game state mutation:
|
||||
renderVersion++;
|
||||
```
|
||||
|
||||
Guard data is passed to templates as plain object snapshots, not class instances.
|
||||
|
||||
## Data Flow: Player Turn
|
||||
|
||||
```
|
||||
Player Input (Arrow Key / WASD / Cell Click)
|
||||
↓
|
||||
Game.svelte onKeyDown() or onCellClick()
|
||||
↓
|
||||
handleMove(direction)
|
||||
├→ player.move(direction) → validate bounds + walls
|
||||
↓
|
||||
turnManager.nextTurn(grid, player, guards)
|
||||
├→ Check goal (win condition, checked BEFORE guard update)
|
||||
├→ grid.clearAllLight()
|
||||
├→ guards.forEach(g => g.onTurnChange(allGuards))
|
||||
│ ├→ RotatingGuard: rotate + castBeam (with mirror reflection)
|
||||
│ ├→ BlinkingGuard: toggle isOn + updateLight
|
||||
│ ├→ PatrollingGuard: advance path + updateLight
|
||||
│ └→ MirrorGuard: light own cell
|
||||
└→ Check detection: grid.isLight(player.row, player.col)
|
||||
↓
|
||||
renderVersion++ → triggers $derived re-computation
|
||||
↓
|
||||
Svelte re-renders: cells, playerRow/Col, guardSnapshots
|
||||
```
|
||||
|
||||
## Mirror Guard Beam Reflection
|
||||
|
||||
```
|
||||
RotatingGuard.castBeam(dir, fromRow, fromCol, range, allGuards, depth)
|
||||
├→ Cast cells in direction up to range
|
||||
├→ Stop at wall or grid boundary
|
||||
├→ If cell contains MirrorGuard:
|
||||
│ ├→ Compute reflected direction (cw or ccw 90°)
|
||||
│ └→ Recursively castBeam from mirror position
|
||||
└→ Max bounce depth: 3 (prevents infinite loops)
|
||||
```
|
||||
|
||||
## Level 12: Escalating Detection
|
||||
|
||||
```
|
||||
checkFinalLevel() — called each turn on final level
|
||||
├→ Manhattan distance to goal <= 4 AND not yet alerted:
|
||||
│ ├→ princessAlerted = true
|
||||
│ ├→ Show finalMessage overlay
|
||||
│ └→ lightRing(radius=1)
|
||||
├→ Already alerted:
|
||||
│ ├→ alertRadius++
|
||||
│ ├→ lightRing(alertRadius) — light all cells within radius of goal
|
||||
│ └→ If player in lit cell → detected = true
|
||||
└→ Light expands one Manhattan ring per turn until player caught
|
||||
```
|
||||
|
||||
## Module Responsibilities
|
||||
|
||||
| Module | Purpose | Key Exports |
|
||||
|--------|---------|------------|
|
||||
| `GridSystem` | Manages grid state, cell types, boundaries | GridSystem class, cell queries |
|
||||
| `Player` | Player character logic, movement validation | Player class, collision detection |
|
||||
| `Guard` | Base + 4 specialized guard AI implementations | Guard, StaticGuard, RotatingGuard, BlinkingGuard, PatrollingGuard |
|
||||
| `TurnManager` | Turn cycle execution, detection checks | TurnManager class, turn flow control |
|
||||
| `LightingSystem` | Light rendering and aggregation from guards | LightingSystem class, light queries |
|
||||
| `LevelManager` | Level loading and initialization | LevelManager class, level data access |
|
||||
| `Levels` | Static level definitions (JSON-like objects) | LEVELS array (12 levels) |
|
||||
| `theme.js` | Centralized UI constants and button factory | COLORS, FONTS, createButton, createSmallButton |
|
||||
| `localization.js` | Multi-language string management | getText, setLanguage, getLanguage, initLanguage |
|
||||
| `progress.js` | Level completion persistence | getProgress, completeLevel |
|
||||
|
||||
## Data Flow: Player Turn to Detection
|
||||
|
||||
```
|
||||
Player Input (Arrow Key / Mouse Click)
|
||||
↓
|
||||
Game.handleInput() → validate move
|
||||
↓
|
||||
Player.move(newRow, newCol) → update position
|
||||
↓
|
||||
GridSystem.isWall() → block invalid moves
|
||||
↓
|
||||
TurnManager.nextTurn()
|
||||
├→ LightingSystem.clearAllLight()
|
||||
├→ For each Guard: guard.onTurnChange() → guard.updateLight()
|
||||
├→ Aggregate all lit cells into GridSystem
|
||||
└→ GridSystem.isLight(playerRow, playerCol)?
|
||||
├→ YES: showDetectionPopup() → lose life → restart level
|
||||
└→ NO: continue gameplay
|
||||
```
|
||||
| Module | File | Purpose |
|
||||
|--------|------|---------|
|
||||
| GridSystem | `src/lib/game/grid-system.js` | Grid state, cell queries, lighting |
|
||||
| Player | `src/lib/game/player.js` | Movement validation, position |
|
||||
| Guards | `src/lib/game/guards.js` | 5 guard types with AI logic |
|
||||
| TurnManager | `src/lib/game/turn-manager.js` | Turn cycle, detection checks |
|
||||
| LevelManager | `src/lib/game/level-manager.js` | Level loading, guard instantiation |
|
||||
| Levels | `src/lib/levels/levels.js` | 12 level definitions |
|
||||
| Localization | `src/lib/localization.js` | Multi-language string management |
|
||||
| Progress | `src/lib/progress.js` | localStorage persistence |
|
||||
| Theme | `src/styles/theme.css` | CSS variables for all colors/fonts |
|
||||
|
||||
## Asset & Resource Management
|
||||
|
||||
- **Sprites**: Phaser circle objects (guards, player) + image assets from `public/assets/`
|
||||
- **Localization**: JSON files (`src/game/locales/en.json`, `vi.json`)
|
||||
- **Levels**: JavaScript objects in `Levels.js` (no external files)
|
||||
- **Progress**: Browser localStorage (`nntv-progress` key)
|
||||
- **Language Preference**: Browser localStorage (`nntv-language` key)
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- **Grid Rendering**: Single graphics object redrawn per frame
|
||||
- **Lighting Calc**: O(guardCount * cellsPerGuard) per turn
|
||||
- **Max Grid**: 10x10 cells for optimal frame rate
|
||||
- **Guard Limit**: 8 guards max per level
|
||||
- **Turn Execution**: Synchronous (no async operations)
|
||||
- **No sprites/images**: Pure CSS rendering (colored divs, borders)
|
||||
- **Localization**: JSON files (`src/lib/locales/en.json`, `vi.json`)
|
||||
- **Levels**: JS objects in `levels.js`
|
||||
- **Progress**: localStorage key `nntv-progress`
|
||||
- **Language**: localStorage key `nntv-language`
|
||||
|
||||
## Build & Deployment
|
||||
|
||||
**Dev Mode:** `npm run dev`
|
||||
- Vite dev server with hot reload
|
||||
- Source maps enabled
|
||||
- Logging to console
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `npm run dev` | Vite dev server at localhost:8080 with HMR |
|
||||
| `npm run build` | Production bundle to `dist/` |
|
||||
|
||||
**Prod Mode:** `npm run build`
|
||||
- Vite bundling with terser minification
|
||||
- Single bundle output to `dist/`
|
||||
- Assets optimized and copied to `dist/assets/`
|
||||
|
||||
**Deployment:** Upload contents of `dist/` to web server (any static host)
|
||||
**Deployment**: Upload `dist/` contents to any static host.
|
||||
-289
@@ -1,289 +0,0 @@
|
||||
# KẾ HOẠCH PHÁT TRIỂN GAME NIGHT NINJA: TWILIGHT VOYAGE
|
||||
|
||||
## 1. TỔNG QUAN DỰ ÁN
|
||||
|
||||
### Thông tin cơ bản
|
||||
- **Tên game**: Night Ninja: Twilight Voyage
|
||||
- **Thể loại**: Puzzle / Stealth / Turn-based
|
||||
- **Nền tảng**: Web (Phaser 3 + Vite)
|
||||
- **Đối tượng người chơi**: Mọi độ tuổi, yêu thích giải đố
|
||||
- **Độ khó**: Tăng dần theo tiến trình
|
||||
|
||||
### Mô tả game
|
||||
Night Ninja: Twilight Voyage là một game giải đố theo lượt dựa trên lưới ô vuông. Người chơi điều khiển một ninja (hình tròn màu đen) phải vượt qua 12 màn chơi, tránh các khu vực được chiếu sáng để giải cứu công chúa. Game có giao diện tối giản với các hình học cơ bản: ô vuông màu xám (khu vực tối), ô vuông màu vàng (khu vực sáng), ô vuông màu đen (tường không thể đi qua), hình tròn đen (người chơi), và các hình tròn với nhiều màu sắc khác nhau (đại diện cho các loại kẻ thù/trạm gác).
|
||||
|
||||
### Các tính năng chính
|
||||
- Hệ thống 12 màn chơi với độ khó tăng dần
|
||||
- Cơ chế stealth dựa trên tránh ánh sáng
|
||||
- Nhiều loại trạm gác và chướng ngại vật khác nhau
|
||||
- Hệ thống 3 mạng sống xuyên suốt trò chơi
|
||||
- Màn cuối với cái kết bất ngờ, không thể chiến thắng
|
||||
|
||||
## 2. THIẾT KẾ GAME
|
||||
|
||||
### Cốt truyện
|
||||
Công chúa cà rốt của vương quốc rau củ quả bị mất tích. Người chơi hóa thân thành ninja thỏ, vượt qua các màn để giải cứu công chúa. Tuy nhiên, ở màn cuối cùng, người chơi không thể tiếp cận công chúa vì toàn bộ bản đồ sẽ bật sáng khi đến gần, và game kết thúc với thông báo "Thật tiếc, kiếp này ninja không thể giải cứu công chúa rồi."
|
||||
|
||||
### Gameplay
|
||||
- **Mục tiêu chính**: Vượt qua 12 màn chơi để tiếp cận công chúa
|
||||
- **Cơ chế chơi**:
|
||||
- Di chuyển theo lượt trên lưới ô vuông (mỗi lượt di chuyển 1 ô)
|
||||
- Tránh các ô vuông màu vàng (được chiếu sáng)
|
||||
- Không thể đi qua các ô vuông màu đen (tường)
|
||||
- Các trạm gác (hình tròn) có các pattern khác nhau để tạo ra ánh sáng
|
||||
- **Điều kiện thắng/thua**:
|
||||
- Thắng: Đến được vị trí đích của mỗi màn
|
||||
- Thua: Người chơi bước vào ô sáng hoặc hết 3 mạng
|
||||
|
||||
### Đối tượng Game
|
||||
- **Người chơi**: Hình tròn màu đen
|
||||
- **Trạm gác/Kẻ thù**:
|
||||
- Hình tròn màu đỏ: Trạm gác cố định (luôn chiếu sáng các ô xác định)
|
||||
- Hình tròn màu xanh: Trạm gác xoay (xoay và chiếu sáng 1 ô kế bên mỗi lượt)
|
||||
- Hình tròn màu vàng: Trạm gác nhấp nháy (bật/tắt ánh sáng mỗi lượt)
|
||||
- Hình tròn màu tím: Nhân viên gác đêm (di chuyển theo đường định sẵn)
|
||||
- **Môi trường**:
|
||||
- Ô vuông màu xám: Khu vực tối (an toàn)
|
||||
- Ô vuông màu vàng: Khu vực sáng (nguy hiểm)
|
||||
- Ô vuông màu đen: Tường (không thể đi qua)
|
||||
- Ô vuông màu xanh lá: Điểm đích cần đến
|
||||
|
||||
### Thiết kế hình ảnh
|
||||
Game sẽ sử dụng các hình dạng hình học đơn giản thay vì sprites:
|
||||
- **Khu vực tối**: Ô vuông màu xám
|
||||
- **Khu vực sáng**: Ô vuông màu vàng
|
||||
- **Tường**: Ô vuông màu đen
|
||||
- **Người chơi**: Hình tròn màu đen
|
||||
- **Đích đến**: Ô vuông màu xanh lá
|
||||
- **Trạm gác**: Hình tròn nhiều màu sắc
|
||||
|
||||
Không cần đồ họa phức tạp, hoạt ảnh, hoặc âm thanh, làm cho đây là một nguyên mẫu "programmer art".
|
||||
|
||||
## 3. CÁCH TIẾP CẬN PHÁT TRIỂN
|
||||
|
||||
Phát triển game sẽ theo cách tiếp cận tăng dần:
|
||||
1. Đầu tiên thiết lập các cơ chế cốt lõi (di chuyển trên lưới, phát hiện ánh sáng)
|
||||
2. Tạo màn chơi cơ bản đầu tiên
|
||||
3. Dần dần giới thiệu các loại kẻ địch mới với các màn chơi tiến triển
|
||||
4. Cuối cùng, triển khai màn cuối đặc biệt với cái kết bất ngờ của game
|
||||
|
||||
## 4. PHÁT TRIỂN THEO GIAI ĐOẠN
|
||||
|
||||
### Giai đoạn 1: Thiết lập cơ bản
|
||||
1. **Khởi tạo project Phaser + Vite**
|
||||
- Thiết lập cấu trúc thư mục
|
||||
- Cấu hình Vite cho Phaser
|
||||
- Tạo file HTML, CSS cơ bản
|
||||
- Thiết lập entry point cho game
|
||||
|
||||
2. **Tạo các scene cơ bản**
|
||||
- Scene Boot: Khởi tạo game
|
||||
- Scene Preloader: Màn loading (tối giản)
|
||||
- Scene MainMenu: Menu chính với nút bắt đầu
|
||||
- Scene LevelSelect: Chọn màn chơi
|
||||
- Scene Game: Scene chính cho gameplay
|
||||
- Scene GameOver: Màn game over
|
||||
|
||||
3. **Tạo hệ thống Grid**
|
||||
- Xây dựng class GridSystem quản lý lưới ô vuông
|
||||
- Phương thức chuyển đổi tọa độ lưới sang tọa độ pixel
|
||||
- Phương thức vẽ grid lên màn hình
|
||||
- Phương thức kiểm tra vị trí hợp lệ
|
||||
|
||||
### Giai đoạn 2: Core Mechanics
|
||||
|
||||
4. **Xây dựng Player**
|
||||
- Tạo class Player với các thuộc tính: vị trí, số mạng còn lại
|
||||
- Phương thức vẽ người chơi (hình tròn đen)
|
||||
- Phương thức di chuyển theo lượt
|
||||
- Phương thức kiểm tra va chạm với ánh sáng
|
||||
|
||||
5. **Xây dựng hệ thống ánh sáng**
|
||||
- Tạo class LightingSystem quản lý trạng thái sáng/tối
|
||||
- Mảng 2D lưu trữ trạng thái ánh sáng của mỗi ô
|
||||
- Phương thức cập nhật trạng thái ánh sáng mỗi lượt
|
||||
- Phương thức kiểm tra ô có được chiếu sáng không
|
||||
|
||||
6. **Xây dựng các loại trạm gác**
|
||||
- Tạo base class Guard với properties chung
|
||||
- Tạo class StaticGuard: Luôn chiếu sáng các ô cố định
|
||||
- Tạo class RotatingGuard: Xoay và chiếu sáng ô mới mỗi lượt
|
||||
- Tạo class BlinkingGuard: Bật/tắt ánh sáng mỗi lượt
|
||||
- Tạo class PatrollingGuard: Di chuyển theo đường định sẵn
|
||||
|
||||
7. **Hệ thống lượt và turn management**
|
||||
- Tạo class TurnManager quản lý lượt đi
|
||||
- Phương thức nextTurn() để tiến hành lượt mới
|
||||
- Cập nhật vị trí người chơi, trạm gác, ánh sáng sau mỗi lượt
|
||||
- Kiểm tra điều kiện thắng/thua sau mỗi lượt
|
||||
|
||||
### Giai đoạn 3: Thiết kế Level
|
||||
|
||||
8. **Xây dựng Level Manager**
|
||||
- Tạo class LevelManager quản lý các màn chơi
|
||||
- Phương thức load màn chơi từ dữ liệu
|
||||
- Phương thức reset màn chơi khi thua
|
||||
- Phương thức chuyển đến màn tiếp theo
|
||||
|
||||
9. **Thiết kế dữ liệu Level**
|
||||
- Định nghĩa cấu trúc dữ liệu cho mỗi màn chơi
|
||||
- Tạo dữ liệu cho 12 màn với độ khó tăng dần
|
||||
- Thiết kế màn cuối với cơ chế đặc biệt
|
||||
|
||||
**Tiến trình màn chơi**:
|
||||
- **Màn 1**: Di chuyển cơ bản, đến đích (không có trạm gác)
|
||||
- **Màn 2**: Giới thiệu khu vực sáng cần tránh
|
||||
- **Màn 3**: Giới thiệu Trạm gác cố định (màu đỏ)
|
||||
- **Màn 4-5**: Bố cục phức tạp hơn với Trạm gác cố định
|
||||
- **Màn 6**: Giới thiệu Trạm gác xoay (màu xanh)
|
||||
- **Màn 7-8**: Kết hợp Trạm gác cố định và Trạm gác xoay
|
||||
- **Màn 9**: Giới thiệu Trạm gác nhấp nháy (màu vàng)
|
||||
- **Màn 10**: Giới thiệu Trạm gác tuần tra (màu tím)
|
||||
- **Màn 11**: Câu đố phức tạp sử dụng tất cả loại trạm gác
|
||||
- **Màn 12**: Màn cuối với cái kết bất ngờ (không thể giải cứu công chúa)
|
||||
|
||||
10. **Xây dựng Level Factory**
|
||||
- Tạo class LevelFactory tạo các đối tượng trong level
|
||||
- Phương thức tạo người chơi, trạm gác từ dữ liệu
|
||||
- Phương thức thiết lập vị trí và kích thước của grid
|
||||
- Phương thức thiết lập điểm đích
|
||||
|
||||
### Giai đoạn 4: UI và Game Flow
|
||||
|
||||
11. **Xây dựng UI trong Game Scene**
|
||||
- Hiển thị số mạng còn lại
|
||||
- Hiển thị số màn chơi hiện tại
|
||||
- Nút tạm dừng và menu tạm dừng
|
||||
- Hiển thị hướng dẫn đơn giản
|
||||
|
||||
12. **Hoàn thiện Menu và màn Game Over**
|
||||
- Hoàn thiện MainMenu với nút Start
|
||||
- Hoàn thiện LevelSelect với các level có thể chọn
|
||||
- Hoàn thiện GameOver với thông báo phù hợp
|
||||
- Hiển thị thông báo đặc biệt cho màn cuối
|
||||
|
||||
13. **Xây dựng Game State Manager**
|
||||
- Tạo class GameStateManager quản lý trạng thái game
|
||||
- Lưu trữ số mạng, màn chơi hiện tại
|
||||
- Phương thức reset game
|
||||
- Lưu trữ trạng thái game (localStorage)
|
||||
|
||||
### Giai đoạn 5: Hoàn thiện và Tối ưu
|
||||
|
||||
14. **Hoàn thiện Input Controls**
|
||||
- Hỗ trợ điều khiển phím mũi tên
|
||||
- Hỗ trợ điều khiển chuột (click vào ô muốn di chuyển)
|
||||
- Xử lý input trong khi game đang tạm dừng
|
||||
|
||||
15. **Tối ưu hiệu suất**
|
||||
- Sử dụng object pooling cho các đối tượng thường xuyên tạo/hủy
|
||||
- Tối ưu render chỉ vẽ lại các ô thay đổi
|
||||
- Sử dụng dirty flag pattern để giảm tính toán
|
||||
|
||||
16. **Testing và Debug**
|
||||
- Thêm chế độ debug hiển thị thông tin grid
|
||||
- Tạo công cụ debug để test nhanh các màn chơi
|
||||
- Thử nghiệm full playthrough
|
||||
|
||||
17. **Triển khai màn cuối với cơ chế đặc biệt**
|
||||
- Logic đặc biệt cho màn 12
|
||||
- Trigger toàn bộ map sáng khi gần đến công chúa
|
||||
- Thông báo kết thúc game đặc biệt
|
||||
|
||||
## 5. CẤU TRÚC DỰ ÁN
|
||||
|
||||
### Tổ chức tệp (Dựa trên Phaser Vite Template)
|
||||
src/
|
||||
├── game/
|
||||
│ ├── objects/ # Các đối tượng game (Player, Guards, v.v.)
|
||||
│ │ ├── Player.js
|
||||
│ │ ├── Guard.js
|
||||
│ │ ├── GridSystem.js
|
||||
│ │ └── TurnManager.js
|
||||
│ ├── levels/ # Định nghĩa các màn chơi
|
||||
│ │ ├── LevelManager.js
|
||||
│ │ └── Levels.js # Dữ liệu màn chơi
|
||||
│ └── scenes/ # Các scene Phaser
|
||||
│ ├── Boot.js # (đã tồn tại)
|
||||
│ ├── Preloader.js # (đã tồn tại)
|
||||
│ ├── MainMenu.js # (đã tồn tại)
|
||||
│ ├── Game.js # Scene game chính
|
||||
│ └── GameOver.js # (đã tồn tại)
|
||||
|
||||
### Tích hợp với dự án hiện có
|
||||
|
||||
Game sẽ được tích hợp với cấu trúc dự án Phaser hiện có:
|
||||
|
||||
1. Tái sử dụng luồng scene hiện tại (Boot → Preloader → MainMenu → Game → GameOver)
|
||||
2. Thêm các đối tượng game và quản lý mới trong scene Game
|
||||
3. Mở rộng mã hiện có thay vì thay thế nó
|
||||
|
||||
## 6. CÁC MỐC PHÁT TRIỂN
|
||||
|
||||
### Mốc 1: Cơ chế cốt lõi
|
||||
- [x] Thiết lập dự án sử dụng Phaser + Vite
|
||||
- [ ] Triển khai hệ thống lưới
|
||||
- [ ] Di chuyển người chơi và phát hiện va chạm
|
||||
- [ ] Hệ thống quản lý lượt
|
||||
- [ ] Điều kiện thắng/thua cơ bản
|
||||
|
||||
### Mốc 2: Cơ chế màn chơi
|
||||
- [ ] Triển khai khu vực sáng tĩnh
|
||||
- [ ] Triển khai loại trạm gác đầu tiên (Trạm gác cố định)
|
||||
- [ ] Hệ thống tải và chuyển đổi màn chơi
|
||||
- [ ] Giao diện cơ bản (mạng còn lại, màn chơi hiện tại)
|
||||
|
||||
### Mốc 3: Các loại kẻ địch
|
||||
- [ ] Triển khai Trạm gác xoay
|
||||
- [ ] Triển khai Trạm gác nhấp nháy
|
||||
- [ ] Triển khai Trạm gác tuần tra
|
||||
- [ ] Thiết kế màn chơi 1-6 giới thiệu dần các cơ chế này
|
||||
|
||||
### Mốc 4: Luồng game
|
||||
- [ ] Hoàn thiện thiết kế tất cả 12 màn chơi
|
||||
- [ ] Triển khai hệ thống mạng sống (3 mạng xuyên suốt tất cả màn chơi)
|
||||
- [ ] Tạo menu chính và màn hình chọn màn chơi
|
||||
- [ ] Triển khai cái kết đặc biệt cho màn cuối
|
||||
|
||||
### Mốc 5: Hoàn thiện
|
||||
- [ ] Triển khai điều khiển cho thiết bị di động
|
||||
- [ ] Cải thiện giao diện và phản hồi
|
||||
- [ ] Màn hình game over và chiến thắng
|
||||
- [ ] Kiểm thử và sửa lỗi
|
||||
|
||||
## 7. HƯỚNG DẪN TRIỂN KHAI
|
||||
|
||||
### Lời khuyên triển khai
|
||||
1. **Triển khai cụ thể cho Phaser**:
|
||||
- Sử dụng cấu trúc scene hiện có trong template
|
||||
- Tận dụng factory đối tượng game của Phaser (`this.add`)
|
||||
- Sử dụng hệ thống input của Phaser cho điều khiển
|
||||
|
||||
2. **Phát triển tiến dần**:
|
||||
- Triển khai hệ thống lưới và di chuyển cơ bản trước
|
||||
- Thêm từng loại trạm gác một
|
||||
- Tạo và kiểm tra một vài màn chơi trước khi thêm các màn phức tạp hơn
|
||||
|
||||
3. **Khi báo cáo tiến độ**:
|
||||
- Nêu rõ bạn đang làm việc trên mốc và nhiệm vụ nào
|
||||
- Giải thích mọi thách thức hoặc cách tiếp cận thay thế đã thực hiện
|
||||
- Liệt kê những gì đang hoạt động và những gì vẫn đang chờ xử lý
|
||||
|
||||
4. **Điểm bắt đầu**:
|
||||
- Bắt đầu với việc triển khai scene Game.js
|
||||
- Tạo GridSystem
|
||||
- Triển khai di chuyển người chơi cơ bản
|
||||
- Sau đó thêm hệ thống lượt trước khi chuyển sang triển khai trạm gác
|
||||
|
||||
### Quy tắc đặt tên
|
||||
- **Classes**: PascalCase (GameScene, GridSystem, Player)
|
||||
- **Methods & Variables**: camelCase (updateLight, isValidPosition)
|
||||
- **Constants**: UPPER_CASE (MAX_LIVES, GRID_SIZE)
|
||||
- **Private Properties**: _camelCase (_privateVariable)
|
||||
|
||||
### Quy tắc tổ chức
|
||||
- Sử dụng OOP đầy đủ với classes và inheritance
|
||||
- Tách rõ trách nhiệm của từng component
|
||||
- Sử dụng các design patterns phù hợp (Factory, State, Observer)
|
||||
- Comment code đầy đủ, rõ ràng
|
||||
- Tạo các helper functions cho các tác vụ lặp lại
|
||||
Reference in new issue
Block a user