Spaces:
Running on Zero
Running on Zero
| # Phaser 3 Game Template | |
| A standardized Phaser 3 game template for rapid 2D web game development. This template provides a consistent architecture and pre-built components that AI coding agents can use to generate games efficiently. | |
| ## Quick Start | |
| ```bash | |
| # Install dependencies | |
| npm install | |
| # Start development server | |
| npm run dev | |
| # Build for production | |
| npm run build | |
| ``` | |
| ## Project Structure | |
| ``` | |
| src/ | |
| ├── main.ts # Game entry point & Phaser configuration | |
| ├── gameConfig.json # All game parameters (health, speed, damage, etc.) | |
| ├── LevelManager.ts # Level flow management | |
| ├── utils.ts # CRITICAL utility functions (DO NOT MODIFY) | |
| ├── characters/ # Player and enemy classes | |
| │ ├── ExamplePlayer.ts # Template - copy then delete/rename | |
| │ └── ExampleEnemy.ts # Template - copy then delete/rename | |
| ├── scenes/ | |
| │ ├── Preloader.ts # Asset loading (STANDARD - minimal changes) | |
| │ ├── TitleScreen.ts # Start screen (customize UI only) | |
| │ ├── BaseLevelScene.ts # Optional level base class | |
| │ ├── UIScene.ts # In-game HUD | |
| │ ├── VictoryUIScene.ts # Level complete screen | |
| │ ├── GameOverUIScene.ts # Death/failure screen | |
| │ └── GameCompleteUIScene.ts # All levels complete screen | |
| ├── styles/ | |
| │ └── tailwind.css # Tailwind CSS for UI styling | |
| └── test/ | |
| └── setup.ts # Test configuration | |
| public/assets/ | |
| ├── asset-pack.json # Asset manifest for Preloader | |
| └── animations.json # Animation definitions with origin data | |
| ``` | |
| ## Key Files Reference | |
| ### main.ts | |
| - Configures Phaser game instance | |
| - Imports and registers all scenes in order: | |
| 1. Preloader (auto-start) | |
| 2. TitleScreen | |
| 3. Level scenes | |
| 4. UI scenes | |
| ### gameConfig.json | |
| All game parameters use **`{ "value": X }` wrapper format** (self-documenting): | |
| ```json | |
| { | |
| "configGroup": { | |
| "parameterName": { | |
| "value": 100, | |
| "type": "number", | |
| "description": "What this does" | |
| } | |
| } | |
| } | |
| ``` | |
| Access in code: `configGroup.parameterName.value` | |
| ### utils.ts - CRITICAL FUNCTIONS | |
| **DO NOT MODIFY these functions. They solve Phaser quirks.** | |
| | Function | Usage | | |
| | -------------------------------- | ------------------------------------------------------------------- | | |
| | `initScale()` | **ALWAYS use** for sprite scaling. Never use `setScale()` directly. | | |
| | `resetOriginAndOffset()` | **ALWAYS call** after `play()` animation. | | |
| | `initUIDom()` | **ALWAYS use** for UI scene DOM elements. | | |
| | `addCollider()` / `addOverlap()` | **ALWAYS use** instead of `scene.physics.add.collider/overlap`. | | |
| | `createTrigger()` | Create attack/detection zones. | | |
| | `updateMeleeTrigger()` | Update melee attack zone position. | | |
| | `createDecoration()` | Create decorative elements. | | |
| | `computeRotation()` | Calculate projectile rotation. | | |
| ### LevelManager.ts | |
| Manages level progression: | |
| ```typescript | |
| // Add your level scene keys here | |
| static readonly LEVEL_ORDER: string[] = [ | |
| "Level1Scene", | |
| "Level2Scene", | |
| // ... | |
| ]; | |
| ``` | |
| ## Animation Format (animations.json) | |
| ```json | |
| { | |
| "anims": [ | |
| { | |
| "key": "player_idle_anim", | |
| "type": "frame", | |
| "frames": [ | |
| { "key": "player_idle_01", "duration": 400 } // idle: 1 frame only | |
| ], | |
| "repeat": -1, | |
| "originX": 0.5, | |
| "originY": 1.0 | |
| }, | |
| { | |
| "key": "player_run_anim", | |
| "type": "frame", | |
| "frames": [ | |
| { "key": "player_run_01", "duration": 400 }, // run: 2 frames | |
| { "key": "player_run_02", "duration": 400 } | |
| ], | |
| "repeat": -1, | |
| "originX": 0.5, | |
| "originY": 1.0 | |
| } | |
| ] | |
| } | |
| ``` | |
| **Important**: `originX` and `originY` are REQUIRED for `utils.resetOriginAndOffset()` to work correctly. Different animations may have different origins (e.g., attack animations often shift left/right). | |
| ## Asset Pack Format (asset-pack.json) | |
| ```json | |
| { | |
| "assetPack": { | |
| "files": [ | |
| { "type": "json", "key": "animations", "url": "assets/animations.json" }, | |
| { | |
| "type": "image", | |
| "key": "player_idle_01", | |
| "url": "assets/player_idle_01.png" | |
| }, | |
| { | |
| "type": "image", | |
| "key": "player_run_01", | |
| "url": "assets/player_run_01.png" | |
| }, | |
| { | |
| "type": "image", | |
| "key": "player_run_02", | |
| "url": "assets/player_run_02.png" | |
| }, | |
| { | |
| "type": "tilemapTiledJSON", | |
| "key": "level1_map", | |
| "url": "assets/level1_map.json" | |
| } | |
| ] | |
| } | |
| } | |
| ``` | |
| ## Creating a New Game | |
| ### 1. Define Game Config | |
| Edit `gameConfig.json` to add your game's parameters. | |
| ### 2. Create Player Class | |
| Copy `ExamplePlayer.ts` to create your player (e.g., `Player.ts`), then delete `ExamplePlayer.ts`: | |
| - Load config values | |
| - Implement movement in `update()` | |
| - Implement `takeDamage()` and `die()` | |
| - Add animations | |
| ### 3. Create Enemy Classes | |
| Copy `ExampleEnemy.ts` for each enemy type (e.g., `EnemySoldier.ts`), then delete `ExampleEnemy.ts`: | |
| - Configure stats | |
| - Implement AI in `executeAI()` | |
| - Add unique behaviors | |
| ### 4. Create Level Scenes | |
| Either extend `BaseLevelScene` or create from scratch: | |
| ```typescript | |
| export class Level1Scene extends BaseLevelScene { | |
| constructor() { | |
| super({ key: 'Level1Scene' }); | |
| } | |
| create() { | |
| this.createBaseElements(); | |
| // Level-specific setup | |
| } | |
| update(time, delta) { | |
| this.baseUpdate(time, delta); | |
| // Level-specific updates | |
| } | |
| // Implement abstract methods... | |
| } | |
| ``` | |
| ### 5. Register Levels | |
| 1. Import in `main.ts` | |
| 2. Add to `game.scene.add()` | |
| 3. Add key to `LevelManager.LEVEL_ORDER` | |
| ### 6. Customize UI | |
| Modify the `createDOMUI()` methods in: | |
| - `TitleScreen.ts` - Start screen design | |
| - `UIScene.ts` - In-game HUD | |
| - Victory/GameOver scenes - End screens | |
| ## Standard Dimensions | |
| | Element | Standard Height | Notes | | |
| | ---------------- | --------------- | ------------------------------ | | |
| | Player | 128px | Standard human-sized character | | |
| | Small enemy | 48-64px | Knee to waist height | | |
| | Medium enemy | 80-100px | Slightly smaller than player | | |
| | Large enemy/Boss | 150-256px | 1.5x to 2x player size | | |
| | Tile size | 64px | Standard tile dimension | | |
| ## UI Styling | |
| UI uses Tailwind CSS with custom pixel-art styled components: | |
| - `game-pixel-container-*` - Pixel-styled containers | |
| - `game-pixel-container-slot-*` - Progress bar backgrounds | |
| - `game-pixel-container-progress-fill-*` - Progress bar fills | |
| - `game-pixel-container-clickable-*` - Clickable buttons | |
| ## Scene Lifecycle | |
| 1. **Preloader** → Loads all assets | |
| 2. **TitleScreen** → Press Enter to start | |
| 3. **Level1Scene** + **UIScene** (parallel) → Gameplay | |
| 4. On victory: **VictoryUIScene** → Next level OR **GameCompleteUIScene** → Title | |
| 5. On death: **GameOverUIScene** → Restart level | |
| ## Common Patterns | |
| ### Playing Animations | |
| ```typescript | |
| // CORRECT - always use this pattern | |
| playAnimation(animKey: string): void { | |
| this.play(animKey, true); | |
| utils.resetOriginAndOffset(this, this.facingDirection); | |
| } | |
| ``` | |
| ### Scaling Sprites | |
| ```typescript | |
| // CORRECT - always use initScale | |
| utils.initScale( | |
| sprite, | |
| { x: 0.5, y: 1.0 }, // origin | |
| undefined, // maxWidth (optional) | |
| 128, // maxHeight | |
| 0.6, // body width factor | |
| 0.85, // body height factor | |
| ); | |
| // WRONG - never do this | |
| sprite.setScale(2); | |
| sprite.setDisplaySize(100, 100); | |
| ``` | |
| ### Adding Collisions | |
| ```typescript | |
| // CORRECT - guaranteed parameter order | |
| utils.addCollider(this, player, enemies, (player, enemy) => { | |
| player.takeDamage(enemy.damage); | |
| }); | |
| // WRONG - parameter order may be swapped | |
| this.physics.add.collider(player, enemies, callback); | |
| ``` | |
| ## Development Tips | |
| 1. **Always test animations** - Make sure `originX/Y` in animations.json are correct | |
| 2. **Use groups** - Add enemies/decorations to groups for easy management | |
| 3. **Check health** - Use `getHealthPercentage()` for UI updates | |
| 4. **Clean up events** - Always remove event listeners in `cleanupEventListeners()` | |
| 5. **Prevent double-triggers** - Use flags like `isStarting`, `isRestarting` | |
| ## License | |
| MIT | |