fisrt commit
This commit is contained in:
944
docs/ARCHITECTURE.md
Normal file
944
docs/ARCHITECTURE.md
Normal file
@ -0,0 +1,944 @@
|
||||
# Architecture
|
||||
|
||||
Technical architecture for the Roguelite Platformer game.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── main.ts # Entry point, Phaser config
|
||||
├── types/ # TypeScript interfaces
|
||||
│ ├── index.ts # Re-exports
|
||||
│ ├── game-state.ts # RunState, MetaState
|
||||
│ ├── entities.ts # EnemyConfig, HazardConfig
|
||||
│ ├── upgrades.ts # Upgrade, UpgradeEffect
|
||||
│ └── level-gen.ts # RoomTemplate, SpawnPoint
|
||||
│
|
||||
├── config/ # Configuration
|
||||
│ ├── game.config.ts # Phaser config
|
||||
│ ├── physics.config.ts # Arcade physics settings
|
||||
│ ├── controls.config.ts # Key bindings
|
||||
│ ├── balance.config.ts # Balance (speeds, timings)
|
||||
│ └── upgrades.config.ts # All shop upgrades
|
||||
│
|
||||
├── scenes/ # Phaser scenes
|
||||
│ ├── BootScene.ts # Initialization
|
||||
│ ├── PreloadScene.ts # Asset loading
|
||||
│ ├── MenuScene.ts # Main menu
|
||||
│ ├── GameScene.ts # Core gameplay
|
||||
│ ├── UIScene.ts # HUD (parallel with GameScene)
|
||||
│ ├── PauseScene.ts # Pause menu
|
||||
│ ├── ShopScene.ts # Upgrade shop
|
||||
│ └── GameOverScene.ts # Death screen
|
||||
│
|
||||
├── entities/ # Game objects
|
||||
│ ├── Player.ts # Player entity
|
||||
│ ├── PlayerController.ts # Controls + game feel
|
||||
│ ├── enemies/ # Enemy types
|
||||
│ │ ├── Enemy.ts # Base class
|
||||
│ │ ├── Patroller.ts # Patrol enemy
|
||||
│ │ ├── Jumper.ts # Jumping enemy
|
||||
│ │ ├── Flyer.ts # Flying enemy
|
||||
│ │ ├── Chaser.ts # Chasing enemy
|
||||
│ │ └── Sprinter.ts # Fast patrol enemy
|
||||
│ ├── Projectile.ts # Player projectile
|
||||
│ ├── Coin.ts # Collectible coin
|
||||
│ ├── PowerUp.ts # Power-up item
|
||||
│ └── hazards/ # Hazard types
|
||||
│ ├── Spikes.ts # Static spikes
|
||||
│ ├── FallingPlatform.ts # Crumbling platform
|
||||
│ ├── Saw.ts # Moving saw
|
||||
│ ├── Turret.ts # Shooting turret
|
||||
│ └── Laser.ts # Toggle laser
|
||||
│
|
||||
├── systems/ # Managers/Systems
|
||||
│ ├── InputManager.ts # Input buffering, abstraction
|
||||
│ ├── AudioManager.ts # Sound and music
|
||||
│ ├── SaveManager.ts # localStorage persistence
|
||||
│ ├── GameStateManager.ts # Run state + Meta state
|
||||
│ ├── UpgradeManager.ts # Upgrade application
|
||||
│ ├── ScoreManager.ts # Score and combo
|
||||
│ ├── ParticleManager.ts # Particle effects
|
||||
│ └── CameraManager.ts # Screen shake
|
||||
│
|
||||
├── level-generation/ # Procedural generation
|
||||
│ ├── LevelGenerator.ts # Main generator
|
||||
│ ├── RoomPlacer.ts # Room placement
|
||||
│ ├── PathValidator.ts # Path validation
|
||||
│ └── templates/ # JSON room templates
|
||||
│
|
||||
├── ui/ # UI components
|
||||
│ ├── HUD.ts # Heads-up display
|
||||
│ ├── Button.ts # Reusable button
|
||||
│ ├── ProgressBar.ts # Progress/health bar
|
||||
│ └── ComboDisplay.ts # Combo counter
|
||||
│
|
||||
└── utils/ # Utilities
|
||||
├── math.ts # Math helpers
|
||||
└── SeededRandom.ts # Seed-based RNG
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scene Architecture
|
||||
|
||||
### Scene Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ BootScene → PreloadScene → MenuScene ─┬→ GameScene ←──┐ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ UIScene │ │
|
||||
│ │ (parallel) │ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ PauseScene │ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ GameOverScene│ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ │ │
|
||||
│ └→ ShopScene ───┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Scene Responsibilities
|
||||
|
||||
| Scene | Responsibility |
|
||||
|-------|---------------|
|
||||
| **BootScene** | Initialize game settings, configure physics |
|
||||
| **PreloadScene** | Load all assets (sprites, audio, tilemaps) |
|
||||
| **MenuScene** | Main menu, navigation to other scenes |
|
||||
| **GameScene** | Core gameplay loop, entity management |
|
||||
| **UIScene** | HUD overlay, runs parallel with GameScene |
|
||||
| **PauseScene** | Pause menu, settings access during gameplay |
|
||||
| **ShopScene** | Meta-progression shop, upgrade purchases |
|
||||
| **GameOverScene** | Death screen, stats, navigation |
|
||||
|
||||
### Scene Communication
|
||||
|
||||
Scenes communicate through:
|
||||
|
||||
1. **Registry** (`this.registry`) - shared data store
|
||||
2. **Events** (`this.events`) - event-based messaging
|
||||
3. **Scene Manager** - scene transitions
|
||||
|
||||
```typescript
|
||||
// Example: GameScene emits coin collection
|
||||
this.events.emit('coin-collected', { amount: 1, total: this.coins });
|
||||
|
||||
// UIScene listens and updates display
|
||||
this.scene.get('GameScene').events.on('coin-collected', this.updateCoinDisplay, this);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State Management
|
||||
|
||||
### Dual-State Pattern
|
||||
|
||||
The game uses two separate state objects:
|
||||
|
||||
```typescript
|
||||
// RunState - reset every run
|
||||
interface RunState {
|
||||
currentLevel: number;
|
||||
coins: number;
|
||||
score: number;
|
||||
combo: number;
|
||||
projectilesAvailable: number;
|
||||
activePowerUp: PowerUpType | null;
|
||||
powerUpTimer: number;
|
||||
hp: number;
|
||||
hasUsedSecondChance: boolean;
|
||||
enemiesStunned: number;
|
||||
timeElapsed: number;
|
||||
levelSeed: string;
|
||||
}
|
||||
|
||||
// MetaState - persists across runs
|
||||
interface MetaState {
|
||||
gasCoins: number;
|
||||
purchasedUpgrades: string[];
|
||||
activeUpgrades: string[];
|
||||
achievements: string[];
|
||||
totalCoinsCollected: number;
|
||||
totalEnemiesStunned: number;
|
||||
totalDeaths: number;
|
||||
highScores: HighScore[];
|
||||
settings: GameSettings;
|
||||
}
|
||||
```
|
||||
|
||||
### State Flow
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ GameStateManager │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────────────────┐ │
|
||||
│ │ RunState │ │ MetaState │ │
|
||||
│ │ (memory) │ │ (localStorage) │ │
|
||||
│ ├─────────────┤ ├─────────────────────────┤ │
|
||||
│ │ level: 1 │ ──death──▶ │ gasCoins += runCoins │ │
|
||||
│ │ coins: 42 │ │ totalDeaths++ │ │
|
||||
│ │ score: 1200 │ │ highScores.push(...) │ │
|
||||
│ │ ... │ │ │ │
|
||||
│ └─────────────┘ └─────────────────────────┘ │
|
||||
│ │ │ │
|
||||
│ │ reset on new run │ load on boot │
|
||||
│ ▼ ▼ save on change │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Entity System
|
||||
|
||||
### Entity Hierarchy
|
||||
|
||||
```
|
||||
Phaser.GameObjects.Sprite
|
||||
│
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
│ │ │
|
||||
Player Enemy Hazard
|
||||
│ │ │
|
||||
│ ┌───────┼───────┐ │
|
||||
│ │ │ │ │
|
||||
│ Patroller Flyer Chaser │
|
||||
│ │ │ │
|
||||
│ Jumper Sprinter │
|
||||
│ │
|
||||
│ ┌───────┼───────┐
|
||||
│ │ │ │
|
||||
│ Spikes Saw Laser
|
||||
│ │
|
||||
│ FallingPlatform
|
||||
│ │
|
||||
│ Turret
|
||||
│
|
||||
PlayerController
|
||||
```
|
||||
|
||||
### Enemy States
|
||||
|
||||
```typescript
|
||||
enum EnemyState {
|
||||
ACTIVE = 'active', // Dangerous, kills on contact
|
||||
STUNNED = 'stunned', // Safe, can pass through
|
||||
RECOVERING = 'recovering' // Brief transition state
|
||||
}
|
||||
```
|
||||
|
||||
State machine for enemies:
|
||||
|
||||
```
|
||||
┌─────────┐ hit by projectile ┌─────────┐ timer expires ┌────────────┐
|
||||
│ ACTIVE │ ─────────────────▶ │ STUNNED │ ──────────────▶ │ RECOVERING │
|
||||
└─────────┘ └─────────┘ └────────────┘
|
||||
▲ │
|
||||
│ recovery complete │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Physics Configuration
|
||||
|
||||
### Arcade Physics Settings
|
||||
|
||||
```typescript
|
||||
// physics.config.ts
|
||||
export const PHYSICS_CONFIG = {
|
||||
gravity: { y: 1200 },
|
||||
|
||||
player: {
|
||||
speed: 300,
|
||||
jumpVelocity: -500,
|
||||
acceleration: 2000,
|
||||
drag: 1500,
|
||||
},
|
||||
|
||||
projectile: {
|
||||
speed: 600,
|
||||
lifetime: 1000, // ms
|
||||
},
|
||||
|
||||
enemies: {
|
||||
patroller: { speed: 100 },
|
||||
jumper: { speed: 80, jumpForce: -400 },
|
||||
flyer: { speed: 120 },
|
||||
chaser: { speed: 60 },
|
||||
sprinter: { speed: 200 },
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Collision Groups
|
||||
|
||||
```
|
||||
Player ←→ Enemy (active) = Death
|
||||
Player ←→ Enemy (stunned) = Pass through
|
||||
Player ←→ Hazard = Death
|
||||
Player ←→ Coin = Collect
|
||||
Player ←→ PowerUp = Collect
|
||||
Player ←→ Platform = Land
|
||||
Projectile ←→ Enemy = Stun enemy
|
||||
Projectile ←→ Wall = Destroy (or ricochet)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Game Feel Implementation
|
||||
|
||||
### Coyote Time
|
||||
|
||||
```typescript
|
||||
// PlayerController.ts
|
||||
private coyoteTime = 100; // ms
|
||||
private coyoteTimer = 0;
|
||||
private wasGrounded = false;
|
||||
|
||||
update(delta: number) {
|
||||
if (this.body.onFloor()) {
|
||||
this.coyoteTimer = this.coyoteTime;
|
||||
this.wasGrounded = true;
|
||||
} else if (this.wasGrounded) {
|
||||
this.coyoteTimer -= delta;
|
||||
if (this.coyoteTimer <= 0) {
|
||||
this.wasGrounded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canJump(): boolean {
|
||||
return this.body.onFloor() || this.coyoteTimer > 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Input Buffering
|
||||
|
||||
```typescript
|
||||
// InputManager.ts
|
||||
private jumpBufferTime = 100; // ms
|
||||
private jumpBufferTimer = 0;
|
||||
|
||||
update(delta: number) {
|
||||
if (this.jumpPressed) {
|
||||
this.jumpBufferTimer = this.jumpBufferTime;
|
||||
} else {
|
||||
this.jumpBufferTimer = Math.max(0, this.jumpBufferTimer - delta);
|
||||
}
|
||||
}
|
||||
|
||||
hasBufferedJump(): boolean {
|
||||
return this.jumpBufferTimer > 0;
|
||||
}
|
||||
|
||||
consumeJumpBuffer() {
|
||||
this.jumpBufferTimer = 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Variable Jump Height
|
||||
|
||||
```typescript
|
||||
// PlayerController.ts
|
||||
private minJumpVelocity = -250;
|
||||
private maxJumpVelocity = -500;
|
||||
|
||||
onJumpPressed() {
|
||||
if (this.canJump()) {
|
||||
this.body.setVelocityY(this.maxJumpVelocity);
|
||||
this.isJumping = true;
|
||||
}
|
||||
}
|
||||
|
||||
onJumpReleased() {
|
||||
if (this.isJumping && this.body.velocity.y < this.minJumpVelocity) {
|
||||
this.body.setVelocityY(this.minJumpVelocity);
|
||||
}
|
||||
this.isJumping = false;
|
||||
}
|
||||
```
|
||||
|
||||
### Edge Correction
|
||||
|
||||
```typescript
|
||||
// PlayerController.ts
|
||||
private edgeCorrectionDistance = 4; // pixels
|
||||
|
||||
handleCollision(tile: Phaser.Tilemaps.Tile) {
|
||||
if (this.body.velocity.y < 0) { // Moving upward
|
||||
const overlap = this.getHorizontalOverlap(tile);
|
||||
if (overlap > 0 && overlap <= this.edgeCorrectionDistance) {
|
||||
this.x += overlap * this.getOverlapDirection(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Level Generation
|
||||
|
||||
### Spelunky-Style Room Grid
|
||||
|
||||
```
|
||||
┌─────┬─────┬─────┬─────┐
|
||||
│ S │ │ │ │ S = Start
|
||||
├─────┼─────┼─────┼─────┤ E = Exit
|
||||
│ ↓ │ ←──┤ │ │ ↓ → = Path direction
|
||||
├─────┼─────┼─────┼─────┤
|
||||
│ │ ↓ │ │ │
|
||||
├─────┼─────┼─────┼─────┤
|
||||
│ │ E │ │ │
|
||||
└─────┴─────┴─────┴─────┘
|
||||
```
|
||||
|
||||
### Generation Algorithm
|
||||
|
||||
```typescript
|
||||
// LevelGenerator.ts
|
||||
class LevelGenerator {
|
||||
generateLevel(level: number, seed: string): Level {
|
||||
const rng = new SeededRandom(seed);
|
||||
const config = this.getLevelConfig(level);
|
||||
|
||||
// 1. Create room grid
|
||||
const grid = this.createGrid(config.gridSize);
|
||||
|
||||
// 2. Generate guaranteed path
|
||||
const path = this.generatePath(grid, rng);
|
||||
|
||||
// 3. Place room templates along path
|
||||
this.placeRooms(grid, path, config.difficulty, rng);
|
||||
|
||||
// 4. Fill remaining cells with optional rooms
|
||||
this.fillOptionalRooms(grid, rng);
|
||||
|
||||
// 5. Place entities
|
||||
this.placeCoins(grid, config.coinCount, rng);
|
||||
this.placeEnemies(grid, config.enemyCount, level, rng);
|
||||
this.placeHazards(grid, config.hazardCount, level, rng);
|
||||
this.placePowerUp(grid, rng); // 10% chance
|
||||
|
||||
// 6. Validate
|
||||
if (!this.validatePath(grid)) {
|
||||
return this.generateLevel(level, seed + '_retry');
|
||||
}
|
||||
|
||||
return this.buildLevel(grid);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Room Templates
|
||||
|
||||
```typescript
|
||||
// types/level-gen.ts
|
||||
interface RoomTemplate {
|
||||
id: string;
|
||||
width: number; // tiles
|
||||
height: number; // tiles
|
||||
difficulty: number; // 1-10
|
||||
exits: {
|
||||
top: boolean;
|
||||
bottom: boolean;
|
||||
left: boolean;
|
||||
right: boolean;
|
||||
};
|
||||
tiles: number[][]; // tile IDs
|
||||
spawnPoints: SpawnPoint[];
|
||||
}
|
||||
|
||||
interface SpawnPoint {
|
||||
type: 'coin' | 'enemy' | 'hazard' | 'powerup';
|
||||
x: number;
|
||||
y: number;
|
||||
probability?: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Upgrade System
|
||||
|
||||
### Upgrade Configuration
|
||||
|
||||
```typescript
|
||||
// config/upgrades.config.ts
|
||||
export const UPGRADES: Upgrade[] = [
|
||||
{
|
||||
id: 'light_boots',
|
||||
name: 'Light Boots',
|
||||
description: '+10% movement speed',
|
||||
category: 'character',
|
||||
price: 100,
|
||||
effects: [{ type: 'speed_multiplier', value: 1.1 }],
|
||||
unlockRequirement: null,
|
||||
},
|
||||
{
|
||||
id: 'heavy_armor',
|
||||
name: 'Heavy Armor',
|
||||
description: '+1 HP per run, -15% speed',
|
||||
category: 'character',
|
||||
price: 500,
|
||||
effects: [
|
||||
{ type: 'extra_hp', value: 1 },
|
||||
{ type: 'speed_multiplier', value: 0.85 },
|
||||
],
|
||||
unlockRequirement: null,
|
||||
},
|
||||
// ... more upgrades
|
||||
];
|
||||
```
|
||||
|
||||
### Upgrade Application
|
||||
|
||||
```typescript
|
||||
// UpgradeManager.ts
|
||||
class UpgradeManager {
|
||||
applyUpgrades(player: Player, activeUpgrades: string[]) {
|
||||
const stats = { ...DEFAULT_PLAYER_STATS };
|
||||
|
||||
for (const upgradeId of activeUpgrades) {
|
||||
const upgrade = this.getUpgrade(upgradeId);
|
||||
for (const effect of upgrade.effects) {
|
||||
this.applyEffect(stats, effect);
|
||||
}
|
||||
}
|
||||
|
||||
player.setStats(stats);
|
||||
}
|
||||
|
||||
private applyEffect(stats: PlayerStats, effect: UpgradeEffect) {
|
||||
switch (effect.type) {
|
||||
case 'speed_multiplier':
|
||||
stats.speed *= effect.value;
|
||||
break;
|
||||
case 'jump_multiplier':
|
||||
stats.jumpVelocity *= effect.value;
|
||||
break;
|
||||
case 'extra_hp':
|
||||
stats.maxHp += effect.value;
|
||||
break;
|
||||
case 'extra_projectile':
|
||||
stats.maxProjectiles += effect.value;
|
||||
break;
|
||||
// ... more effect types
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Audio System
|
||||
|
||||
### Audio Manager
|
||||
|
||||
```typescript
|
||||
// AudioManager.ts
|
||||
class AudioManager {
|
||||
private music: Phaser.Sound.BaseSound | null = null;
|
||||
private sfxVolume: number = 1;
|
||||
private musicVolume: number = 0.5;
|
||||
|
||||
playMusic(key: string, loop = true) {
|
||||
if (this.music) this.music.stop();
|
||||
this.music = this.scene.sound.add(key, {
|
||||
loop,
|
||||
volume: this.musicVolume
|
||||
});
|
||||
this.music.play();
|
||||
}
|
||||
|
||||
playSFX(key: string, config?: Phaser.Types.Sound.SoundConfig) {
|
||||
this.scene.sound.play(key, {
|
||||
volume: this.sfxVolume,
|
||||
...config
|
||||
});
|
||||
}
|
||||
|
||||
setMusicVolume(volume: number) {
|
||||
this.musicVolume = volume;
|
||||
if (this.music) this.music.setVolume(volume);
|
||||
}
|
||||
|
||||
setSFXVolume(volume: number) {
|
||||
this.sfxVolume = volume;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Sound Effects List
|
||||
|
||||
| Event | Sound Key |
|
||||
|-------|-----------|
|
||||
| Jump | `sfx_jump` |
|
||||
| Land | `sfx_land` |
|
||||
| Shoot | `sfx_shoot` |
|
||||
| Enemy stunned | `sfx_stun` |
|
||||
| Coin collected | `sfx_coin` |
|
||||
| PowerUp collected | `sfx_powerup` |
|
||||
| Player death | `sfx_death` |
|
||||
| Level complete | `sfx_level_complete` |
|
||||
| Menu select | `sfx_menu_select` |
|
||||
| Purchase | `sfx_purchase` |
|
||||
|
||||
---
|
||||
|
||||
## Save System
|
||||
|
||||
### SaveManager
|
||||
|
||||
```typescript
|
||||
// SaveManager.ts
|
||||
class SaveManager {
|
||||
private readonly SAVE_KEY = 'roguelite_platformer_save';
|
||||
|
||||
save(metaState: MetaState): void {
|
||||
const data = JSON.stringify(metaState);
|
||||
localStorage.setItem(this.SAVE_KEY, data);
|
||||
}
|
||||
|
||||
load(): MetaState | null {
|
||||
const data = localStorage.getItem(this.SAVE_KEY);
|
||||
if (!data) return null;
|
||||
|
||||
try {
|
||||
return JSON.parse(data) as MetaState;
|
||||
} catch {
|
||||
console.error('Failed to parse save data');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
localStorage.removeItem(this.SAVE_KEY);
|
||||
}
|
||||
|
||||
exists(): boolean {
|
||||
return localStorage.getItem(this.SAVE_KEY) !== null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Data Stored
|
||||
|
||||
```typescript
|
||||
interface SaveData {
|
||||
version: string; // For migration
|
||||
metaState: MetaState;
|
||||
lastPlayed: number; // Timestamp
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TypeScript Interfaces
|
||||
|
||||
### Core Types
|
||||
|
||||
```typescript
|
||||
// types/game-state.ts
|
||||
interface RunState {
|
||||
currentLevel: number;
|
||||
coins: number;
|
||||
totalCoinsOnLevel: number;
|
||||
score: number;
|
||||
combo: number;
|
||||
comboTimer: number;
|
||||
projectilesAvailable: number;
|
||||
projectileCooldowns: number[];
|
||||
activePowerUp: PowerUpType | null;
|
||||
powerUpTimer: number;
|
||||
hp: number;
|
||||
maxHp: number;
|
||||
hasUsedSecondChance: boolean;
|
||||
enemiesStunned: number;
|
||||
timeElapsed: number;
|
||||
levelSeed: string;
|
||||
isPaused: boolean;
|
||||
}
|
||||
|
||||
interface MetaState {
|
||||
gasCoins: number;
|
||||
purchasedUpgrades: string[];
|
||||
activeUpgrades: string[];
|
||||
achievements: Achievement[];
|
||||
stats: GlobalStats;
|
||||
highScores: HighScore[];
|
||||
settings: GameSettings;
|
||||
}
|
||||
|
||||
interface GlobalStats {
|
||||
totalCoinsCollected: number;
|
||||
totalEnemiesStunned: number;
|
||||
totalDeaths: number;
|
||||
totalLevelsCompleted: number;
|
||||
totalPlayTime: number;
|
||||
highestLevel: number;
|
||||
highestCombo: number;
|
||||
}
|
||||
|
||||
interface HighScore {
|
||||
score: number;
|
||||
level: number;
|
||||
date: number;
|
||||
seed?: string;
|
||||
}
|
||||
|
||||
interface GameSettings {
|
||||
musicVolume: number;
|
||||
sfxVolume: number;
|
||||
screenShake: boolean;
|
||||
showFPS: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Entity Types
|
||||
|
||||
```typescript
|
||||
// types/entities.ts
|
||||
interface EnemyConfig {
|
||||
type: EnemyType;
|
||||
speed: number;
|
||||
patrolDistance?: number;
|
||||
jumpInterval?: number;
|
||||
flightPattern?: FlightPattern;
|
||||
detectionRange?: number;
|
||||
}
|
||||
|
||||
type EnemyType = 'patroller' | 'jumper' | 'flyer' | 'chaser' | 'sprinter';
|
||||
|
||||
interface HazardConfig {
|
||||
type: HazardType;
|
||||
damage: number;
|
||||
interval?: number; // For turrets, lasers
|
||||
path?: Phaser.Math.Vector2[]; // For saws
|
||||
}
|
||||
|
||||
type HazardType = 'spikes' | 'falling_platform' | 'saw' | 'turret' | 'laser';
|
||||
|
||||
type PowerUpType = 'shield' | 'magnet' | 'clock' | 'coffee' | 'infinity' | 'ghost';
|
||||
|
||||
interface PowerUpConfig {
|
||||
type: PowerUpType;
|
||||
duration: number;
|
||||
effect: () => void;
|
||||
}
|
||||
```
|
||||
|
||||
### Upgrade Types
|
||||
|
||||
```typescript
|
||||
// types/upgrades.ts
|
||||
interface Upgrade {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
category: UpgradeCategory;
|
||||
price: number;
|
||||
effects: UpgradeEffect[];
|
||||
unlockRequirement: UnlockRequirement | null;
|
||||
tradeoff?: string; // Description of downside
|
||||
}
|
||||
|
||||
type UpgradeCategory =
|
||||
| 'character'
|
||||
| 'weapon'
|
||||
| 'survival'
|
||||
| 'risk_reward'
|
||||
| 'cosmetic';
|
||||
|
||||
interface UpgradeEffect {
|
||||
type: EffectType;
|
||||
value: number;
|
||||
}
|
||||
|
||||
type EffectType =
|
||||
| 'speed_multiplier'
|
||||
| 'jump_multiplier'
|
||||
| 'extra_hp'
|
||||
| 'extra_projectile'
|
||||
| 'projectile_cooldown_multiplier'
|
||||
| 'projectile_range_multiplier'
|
||||
| 'stun_duration_multiplier'
|
||||
| 'coin_multiplier'
|
||||
| 'score_multiplier'
|
||||
| 'hitbox_multiplier'
|
||||
| 'enable_double_jump'
|
||||
| 'enable_dash'
|
||||
| 'enable_ricochet'
|
||||
| 'enable_explosive';
|
||||
|
||||
interface UnlockRequirement {
|
||||
type: 'level_reached' | 'coins_collected' | 'deaths' | 'enemies_stunned' | 'achievement';
|
||||
value: number | string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Visual Effects
|
||||
|
||||
### Particle System
|
||||
|
||||
```typescript
|
||||
// ParticleManager.ts
|
||||
class ParticleManager {
|
||||
private emitters: Map<string, Phaser.GameObjects.Particles.ParticleEmitter>;
|
||||
|
||||
createDustEffect(x: number, y: number) {
|
||||
this.emitters.get('dust')?.explode(5, x, y);
|
||||
}
|
||||
|
||||
createStunEffect(x: number, y: number) {
|
||||
this.emitters.get('stars')?.explode(8, x, y);
|
||||
}
|
||||
|
||||
createCoinSparkle(x: number, y: number) {
|
||||
this.emitters.get('sparkle')?.explode(3, x, y);
|
||||
}
|
||||
|
||||
createDeathEffect(x: number, y: number) {
|
||||
this.emitters.get('explosion')?.explode(20, x, y);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Screen Shake
|
||||
|
||||
```typescript
|
||||
// CameraManager.ts
|
||||
class CameraManager {
|
||||
private camera: Phaser.Cameras.Scene2D.Camera;
|
||||
private shakeEnabled: boolean = true;
|
||||
|
||||
shake(intensity: number, duration: number) {
|
||||
if (!this.shakeEnabled) return;
|
||||
this.camera.shake(duration, intensity);
|
||||
}
|
||||
|
||||
microShake() {
|
||||
this.shake(0.002, 50);
|
||||
}
|
||||
|
||||
deathShake() {
|
||||
this.shake(0.01, 200);
|
||||
}
|
||||
|
||||
setShakeEnabled(enabled: boolean) {
|
||||
this.shakeEnabled = enabled;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Squash & Stretch
|
||||
|
||||
```typescript
|
||||
// Player.ts
|
||||
jumpSquash() {
|
||||
this.setScale(0.8, 1.2);
|
||||
this.scene.tweens.add({
|
||||
targets: this,
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
duration: 150,
|
||||
ease: 'Back.out',
|
||||
});
|
||||
}
|
||||
|
||||
landSquash() {
|
||||
this.setScale(1.2, 0.8);
|
||||
this.scene.tweens.add({
|
||||
targets: this,
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
duration: 100,
|
||||
ease: 'Back.out',
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Hitstop
|
||||
|
||||
```typescript
|
||||
// GameScene.ts
|
||||
hitStop(duration: number = 50) {
|
||||
this.physics.pause();
|
||||
this.time.delayedCall(duration, () => {
|
||||
this.physics.resume();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Object Pooling
|
||||
|
||||
```typescript
|
||||
// Projectile pooling
|
||||
class ProjectilePool {
|
||||
private pool: Phaser.GameObjects.Group;
|
||||
|
||||
get(): Projectile {
|
||||
const projectile = this.pool.getFirstDead(true);
|
||||
if (projectile) {
|
||||
projectile.setActive(true).setVisible(true);
|
||||
return projectile;
|
||||
}
|
||||
return this.pool.add(new Projectile(this.scene));
|
||||
}
|
||||
|
||||
release(projectile: Projectile) {
|
||||
projectile.setActive(false).setVisible(false);
|
||||
projectile.body.stop();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Culling
|
||||
|
||||
- Entities outside viewport are deactivated
|
||||
- Physics calculations only for active entities
|
||||
- Particle systems use burst mode, not continuous
|
||||
|
||||
### Asset Loading
|
||||
|
||||
- Sprites loaded as atlases
|
||||
- Audio preloaded in PreloadScene
|
||||
- Level templates loaded on demand
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- State management logic
|
||||
- Level generation algorithms
|
||||
- Upgrade calculations
|
||||
- Collision detection helpers
|
||||
|
||||
### Integration Tests
|
||||
- Scene transitions
|
||||
- Save/load functionality
|
||||
- Input handling
|
||||
|
||||
### Manual Testing
|
||||
- Game feel tuning
|
||||
- Balance verification
|
||||
- Performance profiling
|
||||
211
docs/CONTEXT.md
Normal file
211
docs/CONTEXT.md
Normal file
@ -0,0 +1,211 @@
|
||||
# Project Context
|
||||
|
||||
Quick reference for agents to restore context. Updated after significant actions.
|
||||
|
||||
---
|
||||
|
||||
## Project Summary
|
||||
|
||||
**Type:** Roguelite platformer (browser-based)
|
||||
**Tech Stack:** Phaser 3 + TypeScript + Vite
|
||||
**Current Phase:** Phase 1 - Core Loop (in progress)
|
||||
|
||||
---
|
||||
|
||||
## Key Documents
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| `CLAUDE.md` | Agent instructions, project structure |
|
||||
| `docs/REQUIREMENTS.md` | Full game design, mechanics, upgrades |
|
||||
| `docs/ARCHITECTURE.md` | Technical architecture, patterns, interfaces |
|
||||
| `docs/ROADMAP.md` | Development phases, task checklists |
|
||||
| `docs/CONTEXT.md` | This file - action log for agents |
|
||||
|
||||
---
|
||||
|
||||
## Core Mechanics (Quick Reference)
|
||||
|
||||
- **One-hit kill** platformer (by default)
|
||||
- **Stun projectiles** - 3 max, 3s cooldown each, stun enemies for 3s
|
||||
- **Collect all coins** to complete level
|
||||
- **GasCoins** - meta-currency earned from collected coins
|
||||
- **Shop** - buy upgrades between runs
|
||||
- **Procedural generation** - Spelunky-style room grid (4x4)
|
||||
|
||||
---
|
||||
|
||||
## Game Feel Constants
|
||||
|
||||
```
|
||||
Coyote Time: 100ms
|
||||
Input Buffer: 100ms
|
||||
Edge Correction: 4px
|
||||
Stun Duration: 3s (base)
|
||||
Projectile Cooldown: 3s (base)
|
||||
Max Projectiles: 3 (base)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Action Log
|
||||
|
||||
### 2025-01-17
|
||||
|
||||
**Phase 1 Core Implementation Started**
|
||||
|
||||
1. **Project Initialized**
|
||||
- Vite + TypeScript + Phaser 3 configured
|
||||
- `package.json`, `tsconfig.json`, `vite.config.ts` created
|
||||
- Path aliases (`@/`) configured
|
||||
|
||||
2. **Config Files Created**
|
||||
- `src/config/game.config.ts` - Phaser config (1280x720, Arcade Physics)
|
||||
- `src/config/physics.config.ts` - Movement speeds, gravity, timings
|
||||
- `src/config/controls.config.ts` - Key bindings, game feel constants
|
||||
- `src/config/balance.config.ts` - Scoring, level progression, spawn rates
|
||||
|
||||
3. **Type Definitions Created**
|
||||
- `src/types/game-state.ts` - RunState, MetaState interfaces
|
||||
- `src/types/entities.ts` - Enemy, Hazard, Player configs
|
||||
|
||||
4. **Base Scenes Implemented**
|
||||
- `BootScene` - Initializes registry with state
|
||||
- `PreloadScene` - Generates placeholder textures
|
||||
- `GameScene` - Core gameplay with test level
|
||||
- `UIScene` - HUD (coins, projectiles, score)
|
||||
- `GameOverScene` - Death screen with stats, GasCoin conversion
|
||||
|
||||
5. **Entities Implemented**
|
||||
- `Player` - Movement, jump with game feel (coyote time, input buffer, variable jump)
|
||||
- `Enemy` - Patroller with stun mechanic, visual indicator
|
||||
- `Coin` - Collection with animation
|
||||
- `Projectile` - Firing and collision
|
||||
|
||||
6. **Core Systems Working**
|
||||
- Player movement with responsive controls
|
||||
- Projectile system with cooldowns
|
||||
- Enemy stunning with timer
|
||||
- Coin collection and level completion
|
||||
- Death/restart cycle
|
||||
- HUD updates
|
||||
- GasCoin earning on death
|
||||
- LocalStorage save/load
|
||||
|
||||
### 2025-01-16
|
||||
|
||||
**Documentation Phase Complete**
|
||||
|
||||
1. Created `docs/ARCHITECTURE.md`
|
||||
2. Created `docs/ROADMAP.md`
|
||||
3. Created `docs/CONTEXT.md`
|
||||
|
||||
---
|
||||
|
||||
## Current State
|
||||
|
||||
```
|
||||
[x] Requirements defined (REQUIREMENTS.md)
|
||||
[x] Architecture designed (ARCHITECTURE.md)
|
||||
[x] Roadmap created (ROADMAP.md)
|
||||
[x] Project initialized (Vite + Phaser + TS)
|
||||
[x] Config files created
|
||||
[x] Type definitions created
|
||||
[x] Base scenes implemented
|
||||
[x] Player with game feel
|
||||
[x] Patroller enemy with stun
|
||||
[x] Coins and collection
|
||||
[x] Projectile system
|
||||
[x] Basic HUD
|
||||
[x] Game Over with GasCoins
|
||||
[ ] Particles and visual juice
|
||||
[ ] Audio system
|
||||
[ ] Shop scene
|
||||
[ ] More enemy types
|
||||
[ ] Procedural level generation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Structure (Current)
|
||||
|
||||
```
|
||||
src/
|
||||
├── main.ts # Entry point
|
||||
├── vite-env.d.ts # Vite types
|
||||
├── config/
|
||||
│ ├── game.config.ts
|
||||
│ ├── physics.config.ts
|
||||
│ ├── controls.config.ts
|
||||
│ └── balance.config.ts
|
||||
├── types/
|
||||
│ ├── index.ts
|
||||
│ ├── game-state.ts
|
||||
│ └── entities.ts
|
||||
├── scenes/
|
||||
│ ├── BootScene.ts
|
||||
│ ├── PreloadScene.ts
|
||||
│ ├── GameScene.ts
|
||||
│ ├── UIScene.ts
|
||||
│ └── GameOverScene.ts
|
||||
└── entities/
|
||||
├── Player.ts
|
||||
├── Enemy.ts
|
||||
├── Coin.ts
|
||||
└── Projectile.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Actions
|
||||
|
||||
1. Add particles (dust, stun stars, coin sparkle)
|
||||
2. Add screen shake options
|
||||
3. Add basic sound effects
|
||||
4. Implement ShopScene
|
||||
5. Add more enemy types (Jumper, Flyer)
|
||||
6. Implement procedural level generation
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
npm run dev # Start dev server (http://localhost:3000)
|
||||
npm run build # Production build
|
||||
npm run preview # Preview production build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Decisions Made
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| Phaser 3 Arcade Physics | Simple, performant, good for platformers |
|
||||
| Dual-state pattern | Clean separation of run vs persistent data |
|
||||
| Placeholder textures | Quick iteration, real assets later |
|
||||
| Registry for state | Shared state between scenes |
|
||||
| Arrow function callbacks | Cleaner collision handling |
|
||||
|
||||
---
|
||||
|
||||
## Known Issues
|
||||
|
||||
- None critical at this point
|
||||
|
||||
---
|
||||
|
||||
## How to Use This File
|
||||
|
||||
**For agents starting work:**
|
||||
1. Read this file first for quick context
|
||||
2. Check "Current State" for project status
|
||||
3. Check "Next Actions" for immediate tasks
|
||||
4. Read relevant docs (ARCHITECTURE.md, ROADMAP.md) as needed
|
||||
|
||||
**After completing work:**
|
||||
1. Add entry to "Action Log" with date
|
||||
2. Update "Current State" checkboxes
|
||||
3. Update "Next Actions" if changed
|
||||
4. Note any "Known Issues" discovered
|
||||
412
docs/REQUIREMENTS.md
Normal file
412
docs/REQUIREMENTS.md
Normal file
@ -0,0 +1,412 @@
|
||||
# Game Requirements
|
||||
|
||||
## Overview
|
||||
|
||||
Хардкорный roguelite-платформер с процедурной генерацией уровней. Игрок собирает монетки, избегая врагов и ловушек. Уникальная механика оружия — оглушающие "газовые" снаряды. Между забегами игрок тратит накопленную валюту на апгрейды в магазине.
|
||||
|
||||
---
|
||||
|
||||
## Core Gameplay
|
||||
|
||||
### Цель игры
|
||||
- Собрать все монетки на уровне
|
||||
- Избегать контакта с врагами и ловушками
|
||||
- Пройти как можно больше уровней
|
||||
- Накопить валюту для покупки апгрейдов
|
||||
|
||||
### Персонаж
|
||||
- Базовое управление: движение влево/вправо, прыжок
|
||||
- Оружие: выпускает оглушающие снаряды ("пуки")
|
||||
- Смерть при любом контакте с активным врагом (one-hit kill по умолчанию)
|
||||
|
||||
### Система снарядов
|
||||
- Максимум **3 снаряда** в запасе (базовое значение)
|
||||
- После использования снаряд **восстанавливается через время** (~3 сек)
|
||||
- Нельзя "спамить" — требуется тактическое использование
|
||||
- Снаряд оглушает врага при попадании
|
||||
- Направление выстрела: в сторону движения персонажа
|
||||
|
||||
### Враги
|
||||
|
||||
#### Типы врагов
|
||||
| Тип | Поведение | Появляется с уровня |
|
||||
|-----|-----------|---------------------|
|
||||
| **Патрульный** | Ходит туда-сюда по платформе | 1 |
|
||||
| **Прыгун** | Прыгает по платформам вертикально | 3 |
|
||||
| **Летун** | Летает по фиксированной траектории | 5 |
|
||||
| **Преследователь** | Медленно движется к игроку | 7 |
|
||||
| **Спринтер** | Патрульный, но быстрый | 10 |
|
||||
|
||||
#### Состояния врагов
|
||||
- **Активное**: опасны, убивают при контакте
|
||||
- **Оглушённое**: безопасны, можно проходить сквозь
|
||||
- Оглушение действует **3 секунды** (базовое значение), затем враг восстанавливается
|
||||
- Визуальный индикатор времени оглушения над врагом (круговой таймер)
|
||||
|
||||
### Ловушки
|
||||
|
||||
| Тип | Поведение | Появляется с уровня |
|
||||
|-----|-----------|---------------------|
|
||||
| **Шипы** | Статичные, мгновенная смерть | 2 |
|
||||
| **Падающая платформа** | Падает через 0.5сек после наступания | 4 |
|
||||
| **Пила** | Движется по траектории | 6 |
|
||||
| **Турель** | Стреляет снарядами с интервалом | 8 |
|
||||
| **Лазер** | Включается/выключается по таймеру | 10 |
|
||||
|
||||
### Прогрессия уровней
|
||||
- После сбора всех монеток — переход на следующий уровень
|
||||
- С каждым уровнем сложность увеличивается:
|
||||
- Больше врагов
|
||||
- Новые типы врагов
|
||||
- Появляются ловушки
|
||||
- Больше монеток (нужно больше собрать)
|
||||
- Сложнее структура уровня
|
||||
|
||||
---
|
||||
|
||||
## Game Feel (Критически важно)
|
||||
|
||||
### Coyote Time
|
||||
- Игрок может прыгнуть в течение **100мс** после схода с платформы
|
||||
- Незаметно для игрока, но убирает фрустрацию от "несправедливых" смертей
|
||||
|
||||
### Input Buffering (Jump Buffer)
|
||||
- Если прыжок нажат за **100мс** до приземления — прыжок выполнится автоматически
|
||||
- Предотвращает ощущение "съеденных" инпутов
|
||||
|
||||
### Variable Jump Height
|
||||
- Короткое нажатие = низкий прыжок
|
||||
- Длинное нажатие = высокий прыжок
|
||||
- Даёт точный контроль над персонажем
|
||||
|
||||
### Edge Correction
|
||||
- Если персонаж чуть-чуть не допрыгнул до края платформы — подтянуть на ~4 пикселя
|
||||
- Работает только для небольших расстояний
|
||||
|
||||
### Responsive Controls
|
||||
- Минимальное время разгона/торможения
|
||||
- Мгновенная смена направления
|
||||
- Никакой "скользкости"
|
||||
|
||||
---
|
||||
|
||||
## Visual Juice
|
||||
|
||||
### Частицы
|
||||
- Пыль при приземлении
|
||||
- Пыль при беге (каждые N кадров)
|
||||
- Облачко при выстреле снарядом
|
||||
- "Звёздочки" при оглушении врага
|
||||
- Блеск/свечение монеток
|
||||
- Взрыв частиц при смерти персонажа
|
||||
|
||||
### Screen Shake
|
||||
- Лёгкая тряска при смерти
|
||||
- Микро-тряска при оглушении врага
|
||||
- **Обязательно**: опция отключения в настройках
|
||||
|
||||
### Squash & Stretch
|
||||
- Персонаж вытягивается вертикально при прыжке
|
||||
- Сжимается горизонтально при приземлении
|
||||
- Враги "сплющиваются" при оглушении
|
||||
- Монетки слегка пульсируют
|
||||
|
||||
### Хитстоп (Freeze Frame)
|
||||
- Микро-пауза (2-3 кадра) при попадании снарядом во врага
|
||||
- Усиливает ощущение импакта
|
||||
|
||||
---
|
||||
|
||||
## Meta-Progression System
|
||||
|
||||
### Валюта
|
||||
- **Газокоины** — основная мета-валюта
|
||||
- Все монетки собранные за забег конвертируются в газокоины после смерти
|
||||
- Конверсия: 1 монетка = 1 газокоин
|
||||
- Бонус за пройденные уровни: +10% за каждый уровень
|
||||
|
||||
### Магазин апгрейдов
|
||||
|
||||
Философия: апгрейды **разнообразят** игру и дают **небольшие** преимущества, но НЕ делают её лёгкой. Многие апгрейды — это tradeoff'ы (плюс в одном, минус в другом).
|
||||
|
||||
#### Категория: Персонаж
|
||||
|
||||
| Апгрейд | Эффект | Цена | Примечание |
|
||||
|---------|--------|------|------------|
|
||||
| **Лёгкие ботинки** | +10% скорость бега | 100 | — |
|
||||
| **Пружинные ботинки** | +15% высота прыжка | 150 | — |
|
||||
| **Тяжёлая броня** | +1 жизнь за забег | 500 | -15% скорость |
|
||||
| **Двойной прыжок** | Можно прыгнуть в воздухе | 800 | — |
|
||||
| **Dash** | Рывок по нажатию, 2сек кулдаун | 600 | — |
|
||||
| **Скользкий** | Неуязвим 0.5сек после урона | 400 | Работает только с доп. жизнями |
|
||||
|
||||
#### Категория: Оружие
|
||||
|
||||
| Апгрейд | Эффект | Цена | Примечание |
|
||||
|---------|--------|------|------------|
|
||||
| **Большой запас** | +1 снаряд (макс. 4) | 300 | — |
|
||||
| **Быстрая перезарядка** | -20% время восстановления | 250 | — |
|
||||
| **Дальнобойность** | +30% дальность полёта снаряда | 200 | — |
|
||||
| **Мощное оглушение** | +1сек время оглушения | 350 | — |
|
||||
| **Разрывной снаряд** | Снаряд оглушает врагов в радиусе | 700 | -1 снаряд в запасе |
|
||||
| **Рикошет** | Снаряд отскакивает от стен 1 раз | 450 | — |
|
||||
| **Скорострел** | -40% время перезарядки | 400 | -30% время оглушения |
|
||||
|
||||
#### Категория: Выживание
|
||||
|
||||
| Апгрейд | Эффект | Цена | Примечание |
|
||||
|---------|--------|------|------------|
|
||||
| **Второй шанс** | 1 раз за забег: воскрешение на месте | 1000 | Одноразовый за забег |
|
||||
| **Магнит** | Монетки притягиваются с расстояния | 200 | — |
|
||||
| **Орлиный глаз** | Видно весь уровень на мини-карте | 300 | — |
|
||||
| **Чутьё опасности** | Враги подсвечиваются за экраном | 250 | — |
|
||||
| **Ловкач** | Hitbox персонажа уменьшен на 10% | 600 | — |
|
||||
|
||||
#### Категория: Риск/Награда
|
||||
|
||||
| Апгрейд | Эффект | Цена | Примечание |
|
||||
|---------|--------|------|------------|
|
||||
| **Жадность** | +50% монеток на уровне | 400 | +25% врагов |
|
||||
| **Хардкор** | x2 очки | 300 | Нет coyote time |
|
||||
| **Берсерк** | +30% скорость, бесконечные снаряды | 500 | Активируется на 10сек при 0 HP (перед смертью) |
|
||||
| **Пацифист** | x3 очки за уровень | 350 | Нельзя использовать снаряды |
|
||||
| **Спидран** | +100 очков за каждые 10сек до таймера | 200 | Таймер 60сек на уровень, смерть по истечении |
|
||||
|
||||
#### Категория: Косметика (не влияет на геймплей)
|
||||
|
||||
| Апгрейд | Эффект | Цена |
|
||||
|---------|--------|------|
|
||||
| **Скин: Космонавт** | Новый вид персонажа | 150 |
|
||||
| **Скин: Рыцарь** | Новый вид персонажа | 150 |
|
||||
| **Скин: Ниндзя** | Новый вид персонажа | 150 |
|
||||
| **След: Радуга** | Радужный след при беге | 100 |
|
||||
| **След: Огонь** | Огненный след | 100 |
|
||||
| **Снаряд: Облачко** | Другой вид снаряда | 50 |
|
||||
| **Снаряд: Сердечко** | Другой вид снаряда | 50 |
|
||||
|
||||
### Система разблокировок
|
||||
|
||||
Некоторые апгрейды требуют достижений для разблокировки покупки:
|
||||
|
||||
| Апгрейд | Требование |
|
||||
|---------|------------|
|
||||
| Двойной прыжок | Дойти до уровня 5 |
|
||||
| Dash | Собрать 500 монеток за один забег |
|
||||
| Второй шанс | Умереть 50 раз |
|
||||
| Хардкор | Пройти уровень без использования снарядов |
|
||||
| Берсерк | Оглушить 100 врагов |
|
||||
| Пацифист | Дойти до уровня 3 без снарядов |
|
||||
|
||||
### Баланс хардкорности
|
||||
|
||||
Принципы сохранения сложности:
|
||||
1. **Базовая игра остаётся one-hit kill** — доп. жизни дорогие и имеют штрафы
|
||||
2. **Tradeoff'ы** — большинство сильных апгрейдов имеют минусы
|
||||
3. **Сложность масштабируется** — чем больше апгрейдов, тем сложнее уровни
|
||||
4. **Потолок силы** — апгрейды не стакаются бесконечно
|
||||
5. **Риск/награда** — самые выгодные апгрейды усложняют игру
|
||||
|
||||
---
|
||||
|
||||
## Level Generation
|
||||
|
||||
### Подход: комнатная генерация (Spelunky-style)
|
||||
- Уровень — сетка из "комнат" (например, 4x4)
|
||||
- Каждая комната — готовый шаблон
|
||||
- Алгоритм гарантирует путь от входа до всех монеток
|
||||
- Шаблоны подбираются по сложности уровня
|
||||
|
||||
### Параметры генерации по уровням
|
||||
|
||||
| Уровень | Комнат | Монеток | Врагов | Ловушек |
|
||||
|---------|--------|---------|--------|---------|
|
||||
| 1-2 | 6-8 | 5-8 | 2-3 | 0 |
|
||||
| 3-5 | 8-10 | 8-12 | 4-6 | 1-2 |
|
||||
| 6-9 | 10-12 | 12-16 | 6-8 | 3-4 |
|
||||
| 10+ | 12-16 | 16-20 | 8-12 | 5-6 |
|
||||
|
||||
### Seed система
|
||||
- Каждый уровень имеет seed
|
||||
- Seed отображается на экране паузы
|
||||
- Можно ввести seed для воспроизведения уровня (отдельный режим, без влияния на лидерборд)
|
||||
|
||||
---
|
||||
|
||||
## Scoring System
|
||||
|
||||
### Базовые очки
|
||||
- Монетка: **10 очков**
|
||||
- Завершение уровня: **100 очков × номер уровня**
|
||||
- Оглушение врага: **5 очков**
|
||||
|
||||
### Комбо-система
|
||||
- Сбор монеток без паузы увеличивает множитель
|
||||
- Пауза >2сек сбрасывает комбо
|
||||
- Множители: x1 → x2 → x3 → x5 → x10 (макс)
|
||||
- Попадание снарядом во врага не сбрасывает комбо
|
||||
|
||||
### Бонусы за уровень
|
||||
- **Быстрое прохождение** (<30 сек): +50% очков за уровень
|
||||
- **Без урона** (если есть доп. жизни): +25% очков
|
||||
- **Без снарядов**: +100% очков
|
||||
|
||||
---
|
||||
|
||||
## UI/UX
|
||||
|
||||
### HUD (во время игры)
|
||||
- Счётчик монеток: "собрано / всего"
|
||||
- Индикатор снарядов (иконки с cooldown-анимацией)
|
||||
- Текущее комбо (если активно)
|
||||
- Номер уровня
|
||||
- Очки
|
||||
- Мини-карта (если куплен апгрейд)
|
||||
- HP (если есть доп. жизни)
|
||||
|
||||
### Экран паузы
|
||||
- Продолжить
|
||||
- Настройки
|
||||
- Seed уровня
|
||||
- Выход в меню (с подтверждением)
|
||||
|
||||
### Game Over экран
|
||||
- Финальный счёт
|
||||
- Статистика забега:
|
||||
- Пройдено уровней
|
||||
- Собрано монеток
|
||||
- Оглушено врагов
|
||||
- Время игры
|
||||
- Заработано газокоинов
|
||||
- Кнопка "В магазин"
|
||||
- Кнопка "Играть снова"
|
||||
- Таблица лидеров
|
||||
|
||||
### Главное меню
|
||||
- Играть
|
||||
- Магазин
|
||||
- Лидерборд
|
||||
- Настройки
|
||||
- Достижения
|
||||
|
||||
### Настройки
|
||||
- Громкость музыки
|
||||
- Громкость звуков
|
||||
- Screen shake: вкл/выкл
|
||||
- Показывать FPS
|
||||
- Сбросить прогресс (с подтверждением)
|
||||
|
||||
---
|
||||
|
||||
## Power-ups (внутри забега)
|
||||
|
||||
Редкие предметы, появляющиеся на уровнях:
|
||||
|
||||
| Power-up | Эффект | Длительность |
|
||||
|----------|--------|--------------|
|
||||
| **Щит** | Защита от 1 удара | До использования |
|
||||
| **Магнит** | Притягивает монетки | 15 сек |
|
||||
| **Часы** | Замедляет врагов на 50% | 10 сек |
|
||||
| **Кофе** | +50% скорость персонажа | 10 сек |
|
||||
| **Бесконечность** | Бесконечные снаряды | 8 сек |
|
||||
| **Призрак** | Проход сквозь врагов | 5 сек |
|
||||
|
||||
Появление: 10% шанс на уровне, максимум 1 power-up на уровень.
|
||||
|
||||
---
|
||||
|
||||
## Technical Requirements
|
||||
|
||||
### Платформа
|
||||
- Браузер (desktop)
|
||||
- Поддержка клавиатуры
|
||||
- Возможно: геймпад (future)
|
||||
|
||||
### Управление
|
||||
|
||||
| Действие | Клавиатура | Геймпад (future) |
|
||||
|----------|------------|------------------|
|
||||
| Движение | A/D или ←/→ | Left Stick / D-Pad |
|
||||
| Прыжок | W / ↑ / Space | A / X |
|
||||
| Стрельба | F / J / Enter | B / Square |
|
||||
| Dash (если куплен) | Shift / K | RB / R1 |
|
||||
| Пауза | Escape / P | Start |
|
||||
|
||||
### Производительность
|
||||
- 60 FPS на современных браузерах
|
||||
- Минимальное разрешение: 800x600
|
||||
- Рекомендуемое: 1280x720
|
||||
|
||||
### Хранение данных (MVP)
|
||||
- localStorage для:
|
||||
- Газокоины (валюта)
|
||||
- Купленные апгрейды
|
||||
- Активные апгрейды
|
||||
- Лидерборд (топ-10)
|
||||
- Достижения
|
||||
- Настройки
|
||||
|
||||
---
|
||||
|
||||
## MVP Scope
|
||||
|
||||
### Фаза 1: Core Loop
|
||||
- [ ] Движение персонажа с game feel (coyote time, input buffer, variable jump)
|
||||
- [ ] Система снарядов
|
||||
- [ ] Базовый враг (патрульный)
|
||||
- [ ] Механика оглушения
|
||||
- [ ] Сбор монеток
|
||||
- [ ] Процедурная генерация (простая)
|
||||
- [ ] Переход между уровнями
|
||||
- [ ] Game Over
|
||||
|
||||
### Фаза 2: Juice & Polish
|
||||
- [ ] Частицы (пыль, эффекты)
|
||||
- [ ] Squash & stretch анимации
|
||||
- [ ] Screen shake (с опцией отключения)
|
||||
- [ ] Звуковые эффекты
|
||||
- [ ] Базовая музыка
|
||||
|
||||
### Фаза 3: Meta-Progression
|
||||
- [ ] Система газокоинов
|
||||
- [ ] Магазин с апгрейдами (5-10 базовых)
|
||||
- [ ] Сохранение прогресса
|
||||
- [ ] Экран Game Over со статистикой
|
||||
|
||||
### Фаза 4: Content
|
||||
- [ ] Дополнительные типы врагов (3-4)
|
||||
- [ ] Ловушки (2-3 типа)
|
||||
- [ ] Power-ups (3-4 типа)
|
||||
- [ ] Больше апгрейдов в магазине
|
||||
- [ ] Достижения
|
||||
|
||||
### Фаза 5: Polish
|
||||
- [ ] Комбо-система
|
||||
- [ ] Лидерборд
|
||||
- [ ] Полный UI/UX
|
||||
- [ ] Баланс сложности
|
||||
- [ ] Seed система
|
||||
|
||||
### Отложено на будущее
|
||||
- [ ] Бекенд для глобального лидерборда
|
||||
- [ ] Ежедневные челленджи (один seed на день)
|
||||
- [ ] Боссы
|
||||
- [ ] Мобильная версия
|
||||
- [ ] Мультиплеер (гонка)
|
||||
- [ ] Steam-релиз
|
||||
|
||||
---
|
||||
|
||||
## Достижения
|
||||
|
||||
| Достижение | Условие | Награда |
|
||||
|------------|---------|---------|
|
||||
| Первые шаги | Пройти уровень 1 | 10 газокоинов |
|
||||
| Коллекционер | Собрать 1000 монеток (всего) | 50 газокоинов |
|
||||
| Мастер оглушения | Оглушить 100 врагов | Разблокировка "Берсерк" |
|
||||
| Пацифист | Пройти уровень без снарядов | Разблокировка "Пацифист" |
|
||||
| Марафонец | Дойти до уровня 10 | 100 газокоинов |
|
||||
| Скоростной забег | Пройти 5 уровней за 3 минуты | 75 газокоинов |
|
||||
| Неубиваемый | Пройти 3 уровня с 1HP без урона | 150 газокоинов |
|
||||
| Богач | Накопить 5000 газокоинов | Скин "Золотой" |
|
||||
| Комбо-мастер | Собрать x10 комбо | 50 газокоинов |
|
||||
| Умер 100 раз | Умереть 100 раз | Скин "Призрак" |
|
||||
466
docs/ROADMAP.md
Normal file
466
docs/ROADMAP.md
Normal file
@ -0,0 +1,466 @@
|
||||
# Development Roadmap
|
||||
|
||||
Phased development plan for the Roguelite Platformer.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
| Phase | Focus | Dependencies |
|
||||
|-------|-------|--------------|
|
||||
| 1 | Core Loop | None |
|
||||
| 2 | Juice & Polish | Phase 1 |
|
||||
| 3 | Meta-Progression | Phase 1 |
|
||||
| 4 | Content | Phases 1-3 |
|
||||
| 5 | Polish & Release | Phases 1-4 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Core Loop
|
||||
|
||||
**Goal:** Playable prototype with basic mechanics
|
||||
|
||||
### Project Setup
|
||||
- [ ] Initialize Vite + Phaser 3 + TypeScript project
|
||||
- [ ] Configure ESLint and Prettier
|
||||
- [ ] Set up project structure (`src/`, `assets/`, `docs/`)
|
||||
- [ ] Create `game.config.ts` with Phaser configuration
|
||||
- [ ] Create `physics.config.ts` with Arcade physics settings
|
||||
|
||||
### Base Scenes
|
||||
- [ ] **BootScene** - Initialize game settings
|
||||
- [ ] **PreloadScene** - Asset loading with progress bar
|
||||
- [ ] **GameScene** - Main gameplay scene
|
||||
- [ ] **GameOverScene** - Death screen with restart option
|
||||
|
||||
### Player
|
||||
- [ ] Create `Player.ts` entity class
|
||||
- [ ] Create `PlayerController.ts` for input handling
|
||||
- [ ] Implement horizontal movement (left/right)
|
||||
- [ ] Implement jump mechanics
|
||||
- [ ] Implement **Coyote Time** (100ms grace period)
|
||||
- [ ] Implement **Input Buffering** (100ms jump buffer)
|
||||
- [ ] Implement **Variable Jump Height** (hold for higher jump)
|
||||
- [ ] Implement **Edge Correction** (4px ledge assist)
|
||||
- [ ] Add responsive controls (minimal acceleration/drag)
|
||||
|
||||
### Projectile System
|
||||
- [ ] Create `Projectile.ts` entity class
|
||||
- [ ] Implement projectile firing (direction based on player facing)
|
||||
- [ ] Implement projectile pool (max 3 active)
|
||||
- [ ] Implement cooldown system (~3 seconds per projectile)
|
||||
- [ ] Add projectile UI indicator in HUD
|
||||
|
||||
### Enemy (Patroller)
|
||||
- [ ] Create `Enemy.ts` base class
|
||||
- [ ] Create `Patroller.ts` enemy type
|
||||
- [ ] Implement patrol behavior (back-and-forth movement)
|
||||
- [ ] Implement platform edge detection
|
||||
- [ ] Implement enemy states: ACTIVE, STUNNED
|
||||
- [ ] Implement stun mechanic (3 seconds duration)
|
||||
- [ ] Add visual stun indicator (circular timer)
|
||||
- [ ] Implement collision: active enemy kills player
|
||||
- [ ] Implement collision: stunned enemy is passable
|
||||
|
||||
### Collectibles
|
||||
- [ ] Create `Coin.ts` entity class
|
||||
- [ ] Implement coin collection mechanics
|
||||
- [ ] Add coin counter to HUD
|
||||
- [ ] Implement level completion condition (all coins collected)
|
||||
|
||||
### Level Structure
|
||||
- [ ] Implement basic tilemap loading
|
||||
- [ ] Create simple test level (single room)
|
||||
- [ ] Implement player spawn point
|
||||
- [ ] Implement level exit (triggers on all coins collected)
|
||||
- [ ] Implement level transition logic
|
||||
|
||||
### Core HUD
|
||||
- [ ] Create `UIScene.ts` (parallel overlay)
|
||||
- [ ] Display coin counter (collected/total)
|
||||
- [ ] Display projectile indicators with cooldowns
|
||||
- [ ] Display current level number
|
||||
|
||||
### Game Over
|
||||
- [ ] Implement player death on enemy contact
|
||||
- [ ] Implement player death on hazard contact (spikes)
|
||||
- [ ] Show Game Over screen with score
|
||||
- [ ] Implement restart functionality
|
||||
|
||||
### Phase 1 Completion Criteria
|
||||
- [ ] Player can move, jump, and shoot
|
||||
- [ ] Game feel mechanics working (coyote time, input buffer, variable jump)
|
||||
- [ ] Patroller enemy patrols and can be stunned
|
||||
- [ ] Coins can be collected
|
||||
- [ ] Level transitions work
|
||||
- [ ] Death/restart cycle works
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Juice & Polish
|
||||
|
||||
**Goal:** Game feels good to play
|
||||
|
||||
### Particles
|
||||
- [ ] Create `ParticleManager.ts` system
|
||||
- [ ] **Dust particles** - on landing
|
||||
- [ ] **Dust particles** - while running (periodic)
|
||||
- [ ] **Projectile cloud** - on firing
|
||||
- [ ] **Stun stars** - when enemy stunned
|
||||
- [ ] **Coin sparkle** - coin idle animation
|
||||
- [ ] **Death explosion** - on player death
|
||||
|
||||
### Visual Feedback
|
||||
- [ ] Implement **Squash & Stretch** for player jump/land
|
||||
- [ ] Implement **Squash** for enemy stun
|
||||
- [ ] Add coin pulse animation
|
||||
- [ ] Add projectile trail effect
|
||||
|
||||
### Screen Effects
|
||||
- [ ] Create `CameraManager.ts` system
|
||||
- [ ] Implement **Screen Shake** - micro shake on stun
|
||||
- [ ] Implement **Screen Shake** - stronger shake on death
|
||||
- [ ] Add settings option to disable screen shake
|
||||
|
||||
### Hitstop
|
||||
- [ ] Implement **Freeze Frame** (2-3 frames) on projectile hit
|
||||
- [ ] Apply hitstop to physics pause, not game pause
|
||||
|
||||
### Audio
|
||||
- [ ] Create `AudioManager.ts` system
|
||||
- [ ] **SFX**: Jump
|
||||
- [ ] **SFX**: Land
|
||||
- [ ] **SFX**: Shoot projectile
|
||||
- [ ] **SFX**: Enemy stunned
|
||||
- [ ] **SFX**: Coin collected
|
||||
- [ ] **SFX**: Player death
|
||||
- [ ] **SFX**: Level complete
|
||||
- [ ] **SFX**: Menu selection
|
||||
- [ ] **Music**: Gameplay loop
|
||||
- [ ] **Music**: Menu theme
|
||||
- [ ] Implement volume controls
|
||||
|
||||
### Phase 2 Completion Criteria
|
||||
- [ ] All particle effects implemented
|
||||
- [ ] Squash/stretch animations working
|
||||
- [ ] Screen shake working with toggle option
|
||||
- [ ] Hitstop adds impact to hits
|
||||
- [ ] All sound effects in place
|
||||
- [ ] Background music playing
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Meta-Progression
|
||||
|
||||
**Goal:** Death -> Shop -> New Run cycle
|
||||
|
||||
### Save System
|
||||
- [ ] Create `SaveManager.ts` with localStorage
|
||||
- [ ] Implement save data structure
|
||||
- [ ] Implement save on state change
|
||||
- [ ] Implement load on game start
|
||||
- [ ] Implement save data migration (version support)
|
||||
|
||||
### State Management
|
||||
- [ ] Create `GameStateManager.ts`
|
||||
- [ ] Implement `RunState` (resets each run)
|
||||
- [ ] Implement `MetaState` (persists across runs)
|
||||
- [ ] Implement GasCoin currency system
|
||||
- [ ] Implement coin -> GasCoin conversion (1:1 + level bonus)
|
||||
|
||||
### Shop Scene
|
||||
- [ ] Create `ShopScene.ts`
|
||||
- [ ] Design shop UI layout
|
||||
- [ ] Implement upgrade display (name, description, price)
|
||||
- [ ] Implement purchase mechanics
|
||||
- [ ] Implement upgrade activation/deactivation
|
||||
- [ ] Show owned upgrades vs available upgrades
|
||||
- [ ] Show GasCoin balance
|
||||
|
||||
### Upgrade System
|
||||
- [ ] Create `UpgradeManager.ts`
|
||||
- [ ] Define `upgrades.config.ts` with all upgrades
|
||||
- [ ] Implement upgrade effect application
|
||||
- [ ] Implement 5-10 basic upgrades:
|
||||
- [ ] Light Boots (+10% speed)
|
||||
- [ ] Spring Boots (+15% jump)
|
||||
- [ ] Heavy Armor (+1 HP, -15% speed)
|
||||
- [ ] Large Magazine (+1 projectile)
|
||||
- [ ] Fast Reload (-20% cooldown)
|
||||
- [ ] Range Boost (+30% projectile range)
|
||||
- [ ] Strong Stun (+1s stun duration)
|
||||
- [ ] Magnet (coin attraction)
|
||||
- [ ] Eagle Eye (minimap)
|
||||
- [ ] Danger Sense (enemy highlight)
|
||||
|
||||
### Game Over Enhancement
|
||||
- [ ] Show run statistics:
|
||||
- [ ] Levels completed
|
||||
- [ ] Coins collected
|
||||
- [ ] Enemies stunned
|
||||
- [ ] Time played
|
||||
- [ ] Show GasCoins earned
|
||||
- [ ] Add "Go to Shop" button
|
||||
- [ ] Add "Play Again" button
|
||||
|
||||
### Phase 3 Completion Criteria
|
||||
- [ ] Progress saves correctly
|
||||
- [ ] GasCoins accumulate across runs
|
||||
- [ ] Shop allows purchasing upgrades
|
||||
- [ ] Purchased upgrades affect gameplay
|
||||
- [ ] Game Over shows stats and earnings
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Content
|
||||
|
||||
**Goal:** Gameplay variety
|
||||
|
||||
### Additional Enemies
|
||||
- [ ] **Jumper** - Vertical jumping enemy (level 3+)
|
||||
- [ ] **Flyer** - Fixed flight path enemy (level 5+)
|
||||
- [ ] **Chaser** - Slow pursuit enemy (level 7+)
|
||||
- [ ] **Sprinter** - Fast patrol enemy (level 10+)
|
||||
- [ ] Implement enemy spawn rules by level
|
||||
|
||||
### Hazards
|
||||
- [ ] Create `Hazard.ts` base class
|
||||
- [ ] **Spikes** - Static instant death (level 2+)
|
||||
- [ ] **Falling Platform** - Collapses after 0.5s (level 4+)
|
||||
- [ ] **Saw** - Moving along path (level 6+)
|
||||
- [ ] **Turret** - Shoots at intervals (level 8+)
|
||||
- [ ] **Laser** - Toggles on/off (level 10+)
|
||||
- [ ] Implement hazard spawn rules by level
|
||||
|
||||
### Power-ups
|
||||
- [ ] Create `PowerUp.ts` entity class
|
||||
- [ ] **Shield** - Blocks 1 hit
|
||||
- [ ] **Magnet** - Attracts coins (15s)
|
||||
- [ ] **Clock** - Slows enemies 50% (10s)
|
||||
- [ ] **Coffee** - +50% player speed (10s)
|
||||
- [ ] **Infinity** - Unlimited projectiles (8s)
|
||||
- [ ] **Ghost** - Phase through enemies (5s)
|
||||
- [ ] Implement 10% spawn chance per level
|
||||
- [ ] Add power-up timer to HUD
|
||||
|
||||
### Procedural Generation
|
||||
- [ ] Create `LevelGenerator.ts`
|
||||
- [ ] Create `RoomPlacer.ts` for room grid
|
||||
- [ ] Create `PathValidator.ts` for path validation
|
||||
- [ ] Design room templates (JSON)
|
||||
- [ ] Implement 4x4 room grid system
|
||||
- [ ] Implement guaranteed path algorithm
|
||||
- [ ] Implement difficulty scaling:
|
||||
- [ ] Levels 1-2: 6-8 rooms, 5-8 coins, 2-3 enemies
|
||||
- [ ] Levels 3-5: 8-10 rooms, 8-12 coins, 4-6 enemies
|
||||
- [ ] Levels 6-9: 10-12 rooms, 12-16 coins, 6-8 enemies
|
||||
- [ ] Levels 10+: 12-16 rooms, 16-20 coins, 8-12 enemies
|
||||
- [ ] Create `SeededRandom.ts` for deterministic generation
|
||||
|
||||
### More Upgrades
|
||||
- [ ] **Double Jump** - Unlock: reach level 5
|
||||
- [ ] **Dash** - Unlock: collect 500 coins in one run
|
||||
- [ ] **Second Chance** - Unlock: die 50 times
|
||||
- [ ] **Explosive Projectile** - Area stun, -1 ammo
|
||||
- [ ] **Ricochet** - Bounces off walls
|
||||
- [ ] **Rapid Fire** - -40% cooldown, -30% stun duration
|
||||
- [ ] **Greed** - +50% coins, +25% enemies
|
||||
- [ ] **Hardcore** - x2 score, no coyote time
|
||||
- [ ] **Berserker** - Frenzy mode at 0 HP
|
||||
- [ ] **Pacifist** - x3 score, no projectiles
|
||||
- [ ] **Speedrun** - Time challenge mode
|
||||
|
||||
### Achievement System
|
||||
- [ ] Create achievement tracking
|
||||
- [ ] Implement achievement triggers
|
||||
- [ ] Add achievement notifications
|
||||
- [ ] Create achievement display in menu
|
||||
- [ ] Implement unlock requirements for upgrades
|
||||
|
||||
### Phase 4 Completion Criteria
|
||||
- [ ] All 5 enemy types implemented and balanced
|
||||
- [ ] All 5 hazard types implemented
|
||||
- [ ] All 6 power-ups working
|
||||
- [ ] Procedural generation creates varied levels
|
||||
- [ ] Difficulty scales appropriately
|
||||
- [ ] Additional upgrades purchasable
|
||||
- [ ] Achievements tracking and unlocking
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Polish & Release
|
||||
|
||||
**Goal:** Release-ready product
|
||||
|
||||
### Combo System
|
||||
- [ ] Create `ScoreManager.ts`
|
||||
- [ ] Implement combo multiplier (x1 -> x2 -> x3 -> x5 -> x10)
|
||||
- [ ] Implement 2-second combo timeout
|
||||
- [ ] Add combo display to HUD
|
||||
- [ ] Implement level bonuses:
|
||||
- [ ] Fast completion (<30s): +50% score
|
||||
- [ ] No damage: +25% score
|
||||
- [ ] No projectiles: +100% score
|
||||
|
||||
### Leaderboard
|
||||
- [ ] Implement local leaderboard (top 10)
|
||||
- [ ] Create leaderboard display screen
|
||||
- [ ] Add score entry on new high score
|
||||
- [ ] Show rank on Game Over screen
|
||||
|
||||
### Full UI/UX
|
||||
- [ ] Create `MenuScene.ts` with full menu:
|
||||
- [ ] Play button
|
||||
- [ ] Shop button
|
||||
- [ ] Leaderboard button
|
||||
- [ ] Settings button
|
||||
- [ ] Achievements button
|
||||
- [ ] Create `PauseScene.ts`:
|
||||
- [ ] Continue button
|
||||
- [ ] Settings button
|
||||
- [ ] Show current seed
|
||||
- [ ] Quit to menu (with confirmation)
|
||||
- [ ] Polish all UI transitions
|
||||
- [ ] Add button hover/click feedback
|
||||
|
||||
### Seed System
|
||||
- [ ] Display level seed on pause screen
|
||||
- [ ] Implement seed input mode
|
||||
- [ ] Add "Practice Mode" (seeded, no leaderboard)
|
||||
|
||||
### Settings
|
||||
- [ ] Music volume slider
|
||||
- [ ] SFX volume slider
|
||||
- [ ] Screen shake toggle
|
||||
- [ ] Show FPS toggle
|
||||
- [ ] Reset progress (with confirmation)
|
||||
|
||||
### Balance Pass
|
||||
- [ ] Tune player movement speeds
|
||||
- [ ] Tune jump heights
|
||||
- [ ] Tune projectile cooldowns
|
||||
- [ ] Tune stun durations
|
||||
- [ ] Tune enemy speeds and behaviors
|
||||
- [ ] Tune upgrade costs
|
||||
- [ ] Tune difficulty scaling
|
||||
- [ ] Playtest and iterate
|
||||
|
||||
### Bug Fixing & QA
|
||||
- [ ] Fix known bugs
|
||||
- [ ] Test all features end-to-end
|
||||
- [ ] Test save/load edge cases
|
||||
- [ ] Test on multiple browsers
|
||||
- [ ] Performance optimization
|
||||
- [ ] Memory leak checks
|
||||
|
||||
### Phase 5 Completion Criteria
|
||||
- [ ] Combo system adds depth to gameplay
|
||||
- [ ] Leaderboard encourages replayability
|
||||
- [ ] Full menu navigation working
|
||||
- [ ] Seed system allows practice
|
||||
- [ ] Settings all functional
|
||||
- [ ] Game balanced and fair
|
||||
- [ ] No critical bugs
|
||||
|
||||
---
|
||||
|
||||
## Future (Post-MVP)
|
||||
|
||||
### Backend Integration
|
||||
- [ ] Global leaderboard API
|
||||
- [ ] User accounts (optional)
|
||||
- [ ] Cloud save sync
|
||||
|
||||
### Daily Challenges
|
||||
- [ ] Daily seed generation
|
||||
- [ ] Separate daily leaderboard
|
||||
- [ ] Daily rewards
|
||||
|
||||
### Bosses
|
||||
- [ ] Design boss mechanics
|
||||
- [ ] Implement boss encounters (every 5 levels?)
|
||||
- [ ] Boss-specific rewards
|
||||
|
||||
### Mobile Support
|
||||
- [ ] Touch controls
|
||||
- [ ] UI scaling
|
||||
- [ ] Mobile-specific optimizations
|
||||
|
||||
### Multiplayer
|
||||
- [ ] Race mode (2 players)
|
||||
- [ ] Shared leaderboard
|
||||
- [ ] Ghost replays
|
||||
|
||||
### Platform Release
|
||||
- [ ] Steam integration
|
||||
- [ ] Achievements (Steam)
|
||||
- [ ] Cloud saves (Steam)
|
||||
|
||||
---
|
||||
|
||||
## Task Dependencies
|
||||
|
||||
```
|
||||
Phase 1 (Core Loop)
|
||||
│
|
||||
├──────────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
Phase 2 Phase 3
|
||||
(Juice) (Meta-Progression)
|
||||
│ │
|
||||
└─────────┬────────┘
|
||||
│
|
||||
▼
|
||||
Phase 4 (Content)
|
||||
│
|
||||
▼
|
||||
Phase 5 (Polish)
|
||||
│
|
||||
▼
|
||||
RELEASE
|
||||
│
|
||||
▼
|
||||
Future Updates
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Scope creep | Stick to MVP features per phase |
|
||||
| Game feel issues | Prioritize Phase 2 polish early |
|
||||
| Balance problems | Iterative testing each phase |
|
||||
| Save data corruption | Version migrations, backup system |
|
||||
| Performance issues | Object pooling, culling from start |
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Phase 1
|
||||
- Can play multiple rounds
|
||||
- Death/restart cycle smooth
|
||||
- Player movement feels responsive
|
||||
|
||||
### Phase 2
|
||||
- Game "feels good" to play
|
||||
- Feedback is satisfying
|
||||
- Audio enhances experience
|
||||
|
||||
### Phase 3
|
||||
- Players want to unlock upgrades
|
||||
- Meta loop is engaging
|
||||
- Progress feels meaningful
|
||||
|
||||
### Phase 4
|
||||
- Variety keeps runs interesting
|
||||
- Difficulty curve is fair
|
||||
- Content feels sufficient
|
||||
|
||||
### Phase 5
|
||||
- No critical bugs
|
||||
- Performance is stable
|
||||
- Ready for public release
|
||||
Reference in New Issue
Block a user