Agent skill

dev-phaser-fundamentals

Phaser game configuration, scenes, and lifecycle management

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/dev-phaser-fundamentals

SKILL.md

Phaser Fundamentals

"2D web games made simple – scenes, sprites, and physics."

When to Use This Skill

Use when:

  • Setting up a new Phaser game
  • Creating game scenes
  • Implementing the scene lifecycle (preload/create/update)
  • Configuring game settings (scale, physics, renderer)
  • Setting up the game container and canvas

Quick Start

typescript
import Phaser from "phaser";
import { MainScene } from "./scenes/MainScene";

const config: Phaser.Types.Core.GameConfig = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  parent: "game-container",
  backgroundColor: "#000000",
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH,
  },
  physics: {
    default: "arcade",
    arcade: {
      gravity: { y: 300 },
      debug: false,
    },
  },
  scene: [MainScene],
};

new Phaser.Game(config);

Before/After: Manual DOM vs Phaser Pattern

❌ Before: Manual DOM Manipulation

typescript
// Manual game loop without Phaser
const canvas = document.getElementById("game") as HTMLCanvasElement;
const ctx = canvas.getContext("2d")!;

let playerX = 400;
let playerY = 300;

// Manual asset loading
const playerImg = new Image();
playerImg.src = "assets/player.png";
playerImg.onload = () => {
  gameLoop();
};

// Manual game loop
function gameLoop() {
  // Clear canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // Draw player
  ctx.drawImage(playerImg, playerX, playerY);

  // Handle input manually
  document.addEventListener("keydown", (e) => {
    if (e.key === "ArrowLeft") playerX -= 5;
    // ... more manual input handling
  });

  requestAnimationFrame(gameLoop);
}

Problems:

  • Manual asset loading (no preload queue)
  • No sprite management
  • Manual collision detection
  • No physics engine
  • Scene management is manual

✅ After: Phaser Pattern

typescript
// Phaser handles everything
export class GameScene extends Phaser.Scene {
  private player!: Phaser.Physics.Arcade.Sprite;

  preload() {
    // Built-in asset loading with progress tracking
    this.load.image("player", "assets/player.png");
  }

  create() {
    // Physics-enabled sprite
    this.player = this.physics.add.sprite(400, 300, "player");

    // Built-in input handling
    this.cursors = this.input.keyboard!.createCursorKeys();
  }

  update() {
    // Frame-independent movement
    if (this.cursors.left!.isDown) {
      this.player.setVelocityX(-160);
    }
    // Built-in physics handles position updates
  }
}

const config = {
  // Phaser manages the game loop, canvas, rendering
  scene: [GameScene],
  physics: { default: "arcade" },
};

new Phaser.Game(config);

Benefits:

  • Asset preloading with progress events
  • Built-in physics engine
  • Scene lifecycle management
  • Input handling abstraction
  • Optimized rendering pipeline

Decision Framework

Need Use
Basic 2D game Phaser.AUTO renderer type
Physics platformer Arcade physics with gravity
Physics puzzle Matter physics for realism
Responsive layout Phaser.Scale.FIT with CENTER_BOTH
Multiple scenes Array of scene classes in config

Progressive Guide

Level 1: Basic Scene Setup

typescript
export class MainScene extends Phaser.Scene {
  constructor() {
    super({ key: "MainScene" });
  }

  preload() {
    // Load assets before create()
    this.load.image("player", "assets/player.png");
    this.load.image("background", "assets/bg.png");
  }

  create() {
    // Create game objects
    this.add.image(400, 300, "background");
    this.player = this.physics.add.sprite(400, 300, "player");
  }

  update(time: number, delta: number) {
    // Game loop (60fps)
    // delta = time since last frame in ms
  }
}

Level 2: Scene Configuration with Data

typescript
export class GameScene extends Phaser.Scene {
  constructor() {
    super({ key: "GameScene", active: false });
  }

  init(data: { level: number; score: number }) {
    // Receive data from previous scene
    this.level = data.level || 1;
    this.score = data.score || 0;
  }

  preload() {
    // Load level-specific assets
    this.load.image(`level${this.level}`, `assets/level${this.level}.png`);
  }

  create() {
    // Setup game objects
    this.createPlayer();
    this.createEnemies();
  }

  update(time: number, delta: number) {
    this.updatePlayer();
    this.updateEnemies();
  }
}

Level 3: Game Config with Multiple Scenes

typescript
const config: Phaser.Types.Core.GameConfig = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  parent: "game-container",
  backgroundColor: "#2d2d2d",
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH,
    width: 800,
    height: 600,
  },
  physics: {
    default: "arcade",
    arcade: {
      gravity: { x: 0, y: 1000 },
      debug: false,
    },
  },
  scene: [BootScene, PreloadScene, TitleScene, GameScene, UIScene],
  pipeline: { CustomPipeline: CustomPipeline },
};

Level 4: Custom Game Config Extension

typescript
interface ExtendedGameConfig extends Phaser.Types.Core.GameConfig {
  customSettings: {
    maxPlayers: number;
    gameMode: "deathmatch" | "capture";
  };
}

class CustomGame extends Phaser.Game {
  constructor(config: ExtendedGameConfig) {
    super(config);
    this.customSettings = config.customSettings;
  }
}

Level 5: Scene Manager Control

typescript
export class MainScene extends Phaser.Scene {
  create() {
    // Scene transitions
    this.scene.start("GameScene", { level: 1 });

    // Launch parallel scene (UI overlay)
    this.scene.launch("UIScene");

    // Pause current scene
    this.scene.pause();

    // Sleep scene (stops update but keeps rendering)
    this.scene.sleep("BackgroundScene");

    // Stop and remove scene
    this.scene.stop("OldScene");
  }
}

Anti-Patterns

DON'T:

  • Load assets in create() - use preload()
  • Create new objects in update() - causes GC pressure
  • Use this.scene.restart() frequently - expensive operation
  • Forget to call super() in scene constructor
  • Use hardcoded screen dimensions - use scale manager
  • Mix physics and non-physics objects without planning

DO:

  • Preload all assets in preload() before use
  • Reuse objects with object pooling in update()
  • Use scene data for passing values between scenes
  • Clean up event listeners in shutdown() method
  • Use scale.manager for responsive sizing
  • Group related game objects with this.add.group()

Code Patterns

Scene Lifecycle Management

typescript
export class GameScene extends Phaser.Scene {
  private player!: Phaser.Physics.Arcade.Sprite;
  private enemies!: Phaser.GameObjects.Group;
  private cursors!: Phaser.Types.Input.Keyboard.CursorKeys;

  constructor() {
    super({ key: "GameScene" });
  }

  create() {
    // Always setup shutdown for cleanup
    this.events.once(Phaser.Scenes.Events.SHUTDOWN, this.shutdown, this);
  }

  shutdown() {
    // Clean up listeners
    this.input.keyboard!.off("keydown-ESC");
  }

  update(time: number, delta: number) {
    // Use delta for frame-independent movement
    const dt = delta / 1000; // Convert to seconds
  }
}

Scale Manager Pattern

typescript
const config: Phaser.Types.Core.GameConfig = {
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH,
    width: 800,
    height: 600,
  },
};

// In scene, get scale info
this.scale.width; // Actual canvas width
this.scale.height; // Actual canvas height

Checklist

Before completing Phaser setup:

  • Game config has proper scale settings
  • Physics configured correctly (arcade or matter)
  • Scene keys are unique
  • Assets preloaded before use in create()
  • Update loop is performant (no object creation)
  • Shutdown handlers for cleanup
  • Responsive scaling configured
  • Scene transitions use proper data passing

Common Issues

Issue Solution
Assets not loading Check preload() runs before create()
Physics not working Verify physics config and body type
Scene not updating Check scene is active: true
Canvas size wrong Configure scale manager
Memory leaks Clean up in shutdown()

Reference

Didn't find tool you were looking for?

Be as detailed as possible for better results