AgentSkillsCN

phaser-gamedev

使用 Phaser 3 框架构建 2D 游戏。内容涵盖场景生命周期、精灵、物理引擎(Arcade/Matter)、瓦片地图、动画、输入处理,以及游戏架构。触发条件:“创建 Phaser 游戏”、“添加 Phaser 场景”、“Phaser 精灵”、“Phaser 物理引擎”、“Phaser 游戏开发”。

SKILL.md
--- frontmatter
name: phaser-gamedev
description: >
  Build 2D games with Phaser 3 framework. Covers scene lifecycle, sprites, physics (Arcade/Matter),
  tilemaps, animations, input handling, and game architecture. Trigger: "create phaser game",
  "add phaser scene", "phaser sprite", "phaser physics", "game development with phaser".

Phaser Game Development

Build 2D browser games using Phaser 3's scene-based architecture and physics systems.


STOP: Before Loading Any Spritesheet

Read spritesheets-nineslice.md FIRST.

Spritesheet loading is fragile—a few pixels off causes silent corruption that compounds into broken visuals. The reference file contains the mandatory inspection protocol.

Quick rules (details in reference):

  1. Measure the asset before writing loader code—never guess frame dimensions
  2. Character sprites use SQUARE frames: If you calculate frameWidth=56, try 56 for height first
  3. Different animations have different frame sizes: A run cycle needs wider frames than idle; an attack needs extra width for weapon swing. Measure EACH spritesheet independently
  4. Check for spacing: Gaps between frames require spacing: N in loader config
  5. Verify the math: imageWidth = (frameWidth × cols) + (spacing × (cols - 1))

Reference Files

Read these BEFORE working on the relevant feature:

When working on...Read first
Loading ANY spritesheetspritesheets-nineslice.md
Nine-slice UI panelsspritesheets-nineslice.md
Tiled tilemaps, collision layerstilemaps.md
Physics tuning, groups, poolingarcade-physics.md
Performance issues, object poolingperformance.md
Viewport scaling, responsive gamesSee "Viewport Scaling" section below

Architecture Decisions (Make Early)

Physics System Choice

SystemUse When
ArcadePlatformers, shooters, most 2D games. Fast AABB collisions
MatterPhysics puzzles, ragdolls, realistic collisions. Slower, more accurate
NoneMenu scenes, visual novels, card games

Scene Structure

code
scenes/
├── BootScene.ts      # Asset loading, progress bar
├── MenuScene.ts      # Title screen, options
├── GameScene.ts      # Main gameplay
├── UIScene.ts        # HUD overlay (launched parallel)
└── GameOverScene.ts  # End screen, restart

Scene Transitions

typescript
this.scene.start('GameScene', { level: 1 });     // Stop current, start new
this.scene.launch('UIScene');                     // Run in parallel
this.scene.pause('GameScene');                    // Pause
this.scene.stop('UIScene');                       // Stop

Core Patterns

Game Configuration

typescript
const config: Phaser.Types.Core.GameConfig = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH
  },
  physics: {
    default: 'arcade',
    arcade: { gravity: { y: 300 }, debug: false }
  },
  scene: [BootScene, MenuScene, GameScene]
};

Scene Lifecycle

typescript
class GameScene extends Phaser.Scene {
  init(data) { }      // Receive data from previous scene
  preload() { }       // Load assets (runs before create)
  create() { }        // Set up game objects, physics, input
  update(time, delta) { }  // Game loop, use delta for frame-rate independence
}

Frame-Rate Independent Movement

typescript
// CORRECT: scales with frame rate
this.player.x += this.speed * (delta / 1000);

// WRONG: varies with frame rate
this.player.x += this.speed;

Viewport Scaling

CRITICAL: Use Phaser's Scale Manager for ALL viewport scaling. This is the PRIMARY and ONLY correct approach.

Why Phaser Scale Manager?

Phaser's Scale Manager handles:

  • Responsive viewport sizing
  • Aspect ratio preservation
  • Device pixel ratio (DPR) handling
  • Window resize events
  • Canvas scaling and centering
  • Input coordinate transformation

Manual JavaScript/CSS scaling is an anti-pattern that breaks Phaser's coordinate system, input handling, and physics calculations.

Scale Manager Configuration

The Scale Manager is configured in your game config's scale property:

typescript
const config: Phaser.Types.Core.GameConfig = {
  type: Phaser.AUTO,
  width: 800,   // Base game width
  height: 600,  // Base game height
  scale: {
    mode: Phaser.Scale.FIT,              // Primary scaling mode
    autoCenter: Phaser.Scale.CENTER_BOTH, // Center the game canvas
    parent: 'game-container',            // Optional: parent DOM element
    width: 800,                          // Base width (can differ from top-level)
    height: 600,                         // Base height (can differ from top-level)
    min: { width: 400, height: 300 },    // Optional: minimum size
    max: { width: 1920, height: 1080 },  // Optional: maximum size
  },
  // ... rest of config
};

Common Scaling Modes

ModeDescriptionUse When
Phaser.Scale.FITScales to fit viewport, maintains aspect ratio, may show letterboxingMost common - Games that need to work on all screen sizes
Phaser.Scale.RESIZEGame resizes to match viewport exactly, may distort aspect ratioResponsive layouts that adapt to any size
Phaser.Scale.WIDTH_CONTROLS_HEIGHTWidth matches viewport, height calculated to maintain aspect ratioFixed-width responsive games
Phaser.Scale.HEIGHT_CONTROLS_WIDTHHeight matches viewport, width calculated to maintain aspect ratioFixed-height responsive games
Phaser.Scale.NONENo scaling, canvas stays at base sizeDesktop-only games, fixed-size games

Scaling for 70-80% Viewport Usage

To make the game fill 70-80% of the viewport while maintaining aspect ratio:

typescript
const config: Phaser.Types.Core.GameConfig = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH,
    // Calculate target size as percentage of viewport
    // Phaser will automatically scale to fit while maintaining aspect ratio
  },
  // ... rest of config
};

// In your scene, you can also adjust dynamically:
this.scale.setGameSize(
  Math.floor(window.innerWidth * 0.75),  // 75% of viewport width
  Math.floor(window.innerHeight * 0.75)  // 75% of viewport height
);

Dynamic Resize Handling

Phaser automatically handles window resize events when using Scale Manager. To respond to resize:

typescript
this.scale.on('resize', (gameSize: Phaser.Structs.Size) => {
  // Game has been resized
  // gameSize.width and gameSize.height are the new dimensions
  // Adjust camera, UI, or game elements as needed
});

Accessing Scale Information

typescript
// In any scene:
const scaleManager = this.scale;

// Get current game size (after scaling)
const gameWidth = this.scale.gameSize.width;
const gameHeight = this.scale.gameSize.height;

// Get display size (actual canvas size)
const displayWidth = this.scale.displaySize.width;
const displayHeight = this.scale.displaySize.height;

// Get scale factor
const scaleX = this.scale.displaySize.width / this.scale.gameSize.width;
const scaleY = this.scale.displaySize.height / this.scale.gameSize.height;

Anti-Pattern: Manual JavaScript/CSS Scaling

NEVER do this:

typescript
// WRONG: Manual DOM/CSS scaling
const gameCanvas = document.querySelector('canvas');
gameCanvas.style.width = '75%';
gameCanvas.style.height = '75%';
gameCanvas.style.transform = 'scale(0.75)';

// WRONG: Manual JavaScript resize handlers
window.addEventListener('resize', () => {
  const container = document.getElementById('game-container');
  container.style.width = `${window.innerWidth * 0.75}px`;
  container.style.height = `${window.innerHeight * 0.75}px`;
});

// WRONG: MutationObserver for scaling
const observer = new MutationObserver(() => {
  // Manual scaling logic
});

Problems with manual scaling:

  • Breaks Phaser's coordinate system
  • Input coordinates don't match visual positions
  • Physics calculations become incorrect
  • Camera and viewport calculations fail
  • No automatic DPR handling
  • Resize events not properly coordinated

ALWAYS use Phaser Scale Manager:

typescript
// CORRECT: Use Phaser Scale Manager
const config: Phaser.Types.Core.GameConfig = {
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH,
  },
};

When Skills Don't Provide Enough Detail

If scaling requirements are complex or the skill guidance is insufficient:

  1. Search official Phaser documentation:

    • Use mcp_web_fetch to fetch: https://photonstorm.github.io/phaser3-docs/Phaser.Scale.ScaleManager.html
    • Search for: "Phaser Scale Manager", "Phaser.Scale.FIT", "Phaser viewport scaling"
  2. Search Stack Overflow:

    • Search for: "Phaser 3 scaling", "Phaser responsive game", "Phaser Scale Manager"
  3. Check GitHub discussions:

    • Phaser 3 GitHub issues: "Phaser.Scale" or "scaling" issues

Never fall back to manual JavaScript scaling - always use Phaser's built-in Scale Manager.


Anti-Patterns

Anti-PatternProblemSolution
Manual JavaScript/CSS scalingBreaks coordinate system, input, physicsUse Phaser.Scale config in game config
Global state on windowScene transitions break stateUse scene data, registries
Loading in create()Assets not ready when referencedLoad in preload(), use Boot scene
Frame countingGame speed varies with FPSUse delta / 1000
Matter for simple collisionsUnnecessary complexityArcade handles most 2D games
One giant sceneHard to extendSeparate gameplay/UI/menus
Magic numbersImpossible to balanceConfig objects, constants
No object poolingGC stuttersGroups with setActive(false)

Remember

Phaser provides powerful primitives—scenes, sprites, physics, input—but architecture is your responsibility.

Before coding: What scenes? What entities? How do they interact? What physics model?

Claude can build complete, polished Phaser games. These guidelines illuminate the path—they don't fence it.