Phaser Gamedev

chongdashu/phaserjs-tinyswords/.claude/skills/phaser-gamedev

作者 chongdashuf59f1dca8bf461227c9b5d856764e1e90d8b8e90无许可证37 个星标收录于 2026年10月9日更新于 2026年10月9日仓库8个月前更新

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".

AI 生成的概览

指导使用 Phaser 3 框架开发 2D 浏览器游戏,涵盖场景、精灵、物理、瓦片地图与输入。

功能
提供使用 Phaser 3 开发 2D 浏览器游戏的指导,包括游戏配置、场景生命周期与切换、游戏对象、Arcade 与 Matter 物理、输入处理、动画、资源加载以及 Tiled 瓦片地图集成。还给出推荐的项目结构、常见反模式与变化指引。四份参考文档分别涉及 Arcade 物理、瓦片地图、性能以及精灵表与九宫格 UI。
适用场景
适用于创建或扩展 Phaser 3 游戏时,例如搭建场景、添加精灵或物理、接入输入或集成瓦片地图。也适合审查 Phaser 游戏架构并规避常见问题。
运行要求
不包含脚本,仅为说明文档与参考文档。构建和运行游戏需要带 Phaser 3 库的 JavaScript 环境,以及所开发游戏所需的图像、音频和 Tiled JSON 等资源。

Phaser Game Development

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

Philosophy: Games as Living Systems

Games are not static UIs—they are dynamic systems where entities interact, state evolves, and player input drives everything. Before writing code, think architecturally.

Before building, ask:

  • What scenes does this game need? (Boot, Menu, Game, Pause, GameOver)
  • What entities exist and how do they interact?
  • What state must persist across scenes?
  • What physics model fits? (Arcade for speed, Matter for realism)
  • What input methods will players use?

Core principles:

  1. Scene-First Architecture: Structure games around scenes, not global state
  2. Composition Over Inheritance: Build entities from game objects and components
  3. Physics-Aware Design: Choose physics system before coding collisions
  4. Asset Pipeline Discipline: Preload everything, reference by key
  5. Frame-Rate Independence: Use delta time, not frame counting

Game Configuration

Every Phaser game starts with a configuration object.

Minimal Configuration

javascript
const config = {  type: Phaser.AUTO,           // WebGL with Canvas fallback  width: 800,  height: 600,  scene: [BootScene, GameScene]};
const game = new Phaser.Game(config);

Full Configuration Pattern

javascript
const config = {  type: Phaser.AUTO,  width: 800,  height: 600,  parent: 'game-container',    // DOM element ID  backgroundColor: '#2d2d2d',
  scale: {    mode: Phaser.Scale.FIT,    autoCenter: Phaser.Scale.CENTER_BOTH  },
  physics: {    default: 'arcade',    arcade: {      gravity: { y: 300 },      debug: false              // Enable during development    }  },
  scene: [BootScene, MenuScene, GameScene, GameOverScene]};

Physics System Choice

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

Scene Architecture

Scenes are the fundamental organizational unit. Each scene has a lifecycle.

Scene Lifecycle Methods

javascript
class GameScene extends Phaser.Scene {  constructor() {    super('GameScene');        // Scene key for reference  }
  init(data) {    // Called first. Receive data from previous scene    this.level = data.level || 1;  }
  preload() {    // Load assets. Runs before create()    this.load.image('player', 'assets/player.png');    this.load.spritesheet('enemy', 'assets/enemy.png', {      frameWidth: 32, frameHeight: 32    });  }
  create() {    // Set up game objects, physics, input    this.player = this.physics.add.sprite(100, 100, 'player');    this.cursors = this.input.keyboard.createCursorKeys();  }
  update(time, delta) {    // Game loop. Called every frame    // delta = milliseconds since last frame    this.player.x += this.speed * (delta / 1000);  }}

Scene Transitions

javascript
// Start a new scene (stops current)this.scene.start('GameOverScene', { score: this.score });
// Launch scene in parallel (both run)this.scene.launch('UIScene');
// Pause/resume scenesthis.scene.pause('GameScene');this.scene.resume('GameScene');
// Stop a scenethis.scene.stop('UIScene');

Recommended Scene Structure

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

Game Objects

Everything visible in Phaser is a Game Object.

Common Game Objects

javascript
// Images (static)this.add.image(400, 300, 'background');
// Sprites (can animate, physics-enabled)const player = this.add.sprite(100, 100, 'player');
// Textconst score = this.add.text(16, 16, 'Score: 0', {  fontSize: '32px',  fill: '#fff'});
// Graphics (draw shapes)const graphics = this.add.graphics();graphics.fillStyle(0xff0000);graphics.fillRect(100, 100, 50, 50);
// Containers (group objects)const container = this.add.container(400, 300, [sprite1, sprite2]);
// Tilemapsconst map = this.make.tilemap({ key: 'level1' });

Sprite Creation Patterns

javascript
// Basic spriteconst sprite = this.add.sprite(x, y, 'textureKey');
// Sprite with physics bodyconst sprite = this.physics.add.sprite(x, y, 'textureKey');
// From spritesheet frameconst sprite = this.add.sprite(x, y, 'sheet', frameIndex);
// From atlasconst sprite = this.add.sprite(x, y, 'atlas', 'frameName');

Physics Systems

Arcade Physics (Recommended Default)

Fast, simple physics for most 2D games.

javascript
// Enable physics on spritethis.physics.add.sprite(x, y, 'player');
// Or add physics to existing spritethis.physics.add.existing(sprite);
// Configure bodysprite.body.setVelocity(200, 0);sprite.body.setBounce(0.5);sprite.body.setCollideWorldBounds(true);sprite.body.setGravityY(300);
// Collision detectionthis.physics.add.collider(player, platforms);this.physics.add.overlap(player, coins, collectCoin, null, this);
function collectCoin(player, coin) {  coin.disableBody(true, true);  // Remove from physics and hide  this.score += 10;}

Physics Groups

javascript
// Static group (platforms, walls)const platforms = this.physics.add.staticGroup();platforms.create(400, 568, 'ground').setScale(2).refreshBody();
// Dynamic group (enemies, bullets)const enemies = this.physics.add.group({  key: 'enemy',  repeat: 5,  setXY: { x: 100, y: 0, stepX: 70 }});
enemies.children.iterate(enemy => {  enemy.setBounce(Phaser.Math.FloatBetween(0.4, 0.8));});

Matter Physics

For realistic physics simulations.

javascript
// Configphysics: {  default: 'matter',  matter: {    gravity: { y: 1 },    debug: true  }}
// Create bodiesconst ball = this.matter.add.circle(400, 100, 25);const box = this.matter.add.rectangle(400, 400, 100, 50, { isStatic: true });
// Sprite with Matter bodyconst player = this.matter.add.sprite(100, 100, 'player');player.setFriction(0.005);player.setBounce(0.9);

Input Handling

Keyboard Input

javascript
// Cursor keysthis.cursors = this.input.keyboard.createCursorKeys();
// In update()if (this.cursors.left.isDown) {  player.setVelocityX(-160);} else if (this.cursors.right.isDown) {  player.setVelocityX(160);}
if (this.cursors.up.isDown && player.body.touching.down) {  player.setVelocityY(-330);  // Jump}
// Custom keysthis.spaceKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
// Key eventsthis.input.keyboard.on('keydown-SPACE', () => {  this.fire();});

Pointer/Mouse Input

javascript
// Click/tapthis.input.on('pointerdown', (pointer) => {  console.log(pointer.x, pointer.y);});
// Make object interactivesprite.setInteractive();sprite.on('pointerdown', () => {  sprite.setTint(0xff0000);});sprite.on('pointerup', () => {  sprite.clearTint();});
// Dragthis.input.setDraggable(sprite);this.input.on('drag', (pointer, obj, dragX, dragY) => {  obj.x = dragX;  obj.y = dragY;});

Animations

Creating Animations

javascript
// In create() - define oncethis.anims.create({  key: 'walk',  frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }),  frameRate: 10,  repeat: -1  // Loop forever});
this.anims.create({  key: 'jump',  frames: [{ key: 'player', frame: 4 }],  frameRate: 20});
// From atlasthis.anims.create({  key: 'explode',  frames: this.anims.generateFrameNames('atlas', {    prefix: 'explosion_',    start: 1,    end: 8,    zeroPad: 2  }),  frameRate: 16,  hideOnComplete: true});

Playing Animations

javascript
// Play animationsprite.anims.play('walk', true);  // true = ignore if already playing
// Play oncesprite.anims.play('jump');
// Stopsprite.anims.stop();
// Animation eventssprite.on('animationcomplete', (anim, frame) => {  if (anim.key === 'die') {    sprite.destroy();  }});

Asset Loading

Preload Patterns

javascript
preload() {  // Images  this.load.image('sky', 'assets/sky.png');
  // Spritesheets  this.load.spritesheet('player', 'assets/player.png', {    frameWidth: 32,    frameHeight: 48  });
  // Atlases (TexturePacker)  this.load.atlas('sprites', 'assets/sprites.png', 'assets/sprites.json');
  // Tilemaps  this.load.tilemapTiledJSON('map', 'assets/level1.json');  this.load.image('tiles', 'assets/tileset.png');
  // Audio  this.load.audio('bgm', 'assets/music.mp3');  this.load.audio('sfx', ['assets/sound.ogg', 'assets/sound.mp3']);
  // Progress tracking  this.load.on('progress', (value) => {    console.log(`Loading: ${Math.round(value * 100)}%`);  });}

Boot Scene Pattern

javascript
class BootScene extends Phaser.Scene {  constructor() {    super('BootScene');  }
  preload() {    // Loading bar    const width = this.cameras.main.width;    const height = this.cameras.main.height;
    const progressBar = this.add.graphics();    const progressBox = this.add.graphics();    progressBox.fillStyle(0x222222, 0.8);    progressBox.fillRect(width/2 - 160, height/2 - 25, 320, 50);
    this.load.on('progress', (value) => {      progressBar.clear();      progressBar.fillStyle(0xffffff, 1);      progressBar.fillRect(width/2 - 150, height/2 - 15, 300 * value, 30);    });
    // Load all game assets here    this.load.image('player', 'assets/player.png');    // ... more assets  }
  create() {    this.scene.start('MenuScene');  }}

Tilemaps (Tiled Integration)

Loading and Creating

javascript
preload() {  this.load.tilemapTiledJSON('map', 'assets/map.json');  this.load.image('tiles', 'assets/tileset.png');}
create() {  const map = this.make.tilemap({ key: 'map' });  const tileset = map.addTilesetImage('tileset-name-in-tiled', 'tiles');
  // Create layers (match names from Tiled)  const backgroundLayer = map.createLayer('Background', tileset, 0, 0);  const groundLayer = map.createLayer('Ground', tileset, 0, 0);
  // Enable collision on specific tiles  groundLayer.setCollisionByProperty({ collides: true });  // Or by tile index  groundLayer.setCollisionBetween(1, 100);
  // Add collision with player  this.physics.add.collider(this.player, groundLayer);}

Object Layers

javascript
// Spawn points from Tiled object layerconst spawnPoint = map.findObject('Objects', obj => obj.name === 'spawn');this.player = this.physics.add.sprite(spawnPoint.x, spawnPoint.y, 'player');
// Create objects from layerconst coins = map.createFromObjects('Objects', {  name: 'coin',  key: 'coin'});this.physics.world.enable(coins);

Project Structure

Recommended Organization

game/├── src/│   ├── scenes/│   │   ├── BootScene.js│   │   ├── MenuScene.js│   │   ├── GameScene.js│   │   └── UIScene.js│   ├── gameObjects/│   │   ├── Player.js│   │   ├── Enemy.js│   │   └── Collectible.js│   ├── systems/│   │   ├── InputManager.js│   │   └── AudioManager.js│   ├── config/│   │   └── gameConfig.js│   └── main.js├── assets/│   ├── images/│   ├── audio/│   ├── tilemaps/│   └── fonts/├── index.html└── package.json

ES Module Setup

javascript
// main.jsimport Phaser from 'phaser';import BootScene from './scenes/BootScene';import GameScene from './scenes/GameScene';import { gameConfig } from './config/gameConfig';
const config = {  ...gameConfig,  scene: [BootScene, GameScene]};
new Phaser.Game(config);

Anti-Patterns to Avoid

❌ Global State Soup: Storing game state on window or module globals Why bad: Untrackable bugs, scene transitions break state Better: Use scene data, registries, or dedicated state managers

❌ Loading in Create: Loading assets in create() instead of preload() Why bad: Assets may not be ready when referenced Better: Always load in preload(), use Boot scene for all assets

❌ Frame-Dependent Logic: Using frame count instead of delta time Why bad: Game speed varies with frame rate Better: this.speed * (delta / 1000) for consistent movement

❌ Physics Overkill: Using Matter for simple platformer collisions Why bad: Performance hit, unnecessary complexity Better: Arcade physics handles 90% of 2D game needs

❌ Monolithic Scenes: One giant scene with all game logic Why bad: Unmaintainable, hard to add features Better: Separate scenes for menus, gameplay, UI overlays

❌ Magic Numbers: Hardcoded values scattered in code Why bad: Impossible to balance, inconsistent Better: Config objects, constants files

❌ Ignoring Object Pooling: Creating/destroying objects every frame Why bad: Memory churn, garbage collection stutters Better: Use groups with setActive(false) / setVisible(false)

❌ Synchronous Asset Access: Assuming assets load instantly Why bad: Race conditions, undefined textures Better: Chain scene starts, use load events

❌ Assuming Spritesheet Frame Dimensions: Using guessed frame sizes without verifying Why bad: Wrong dimensions cause silent frame corruption; off-by-pixels compounds into broken visuals Better: Open asset file, measure frames, calculate with spacing/margin, verify math adds up

❌ Ignoring Spritesheet Spacing: Not specifying spacing for gapped spritesheets Why bad: Frames shift progressively; later frames read wrong pixel regions Better: Check source asset for gaps between frames; use spacing: N in loader config

❌ Hardcoding Nine-Slice Colors: Using single background color for all UI panel variants Why bad: Transparent frame edges reveal wrong color for different asset color schemes Better: Per-asset background color config; sample from center frame (frame 4)

❌ Nine-Slice with Padded Frames: Treating the full frame as the slice region when the art is centered/padded inside each tile Why bad: Edge tiles contribute interior fill, showing up as opaque “side bars” inside the panel Better: Trim tiles to their effective content bounds (alpha bbox) and composite/cache a texture; add ~1px overlap + disable smoothing to avoid seams

❌ Scaling Discontinuous UI Art: Stretching a cropped ribbon/banner row that contains internal transparent gaps Why bad: The transparent gutters get stretched, so the UI looks segmented or the fill disappears behind the frame. Better: Slice the asset into caps/center, stretch only the center, and stitch the pieces (with ~1px overlap + smoothing disabled) before rendering at pivot sizes.


Variation Guidance

IMPORTANT: Game implementations should vary based on:

  • Game Genre: Platformer physics differ from top-down shooter physics
  • Target Platform: Mobile needs touch input, desktop can use keyboard
  • Art Style: Pixel art uses nearest-neighbor scaling, HD art uses linear
  • Performance Needs: Many sprites → object pooling; few sprites → simple creation
  • Complexity: Simple games can inline; complex games need class hierarchies

Avoid converging on:

  • Always using 800x600 resolution
  • Always using Arcade physics
  • Always using the same scene structure
  • Copy-pasting boilerplate without adaptation

Quick Reference

Common Physics Properties

javascript
body.setVelocity(x, y)body.setVelocityX(x)body.setBounce(x, y)body.setGravityY(y)body.setCollideWorldBounds(true)body.setImmovable(true)        // For static-like dynamic bodiesbody.setDrag(x, y)body.setMaxVelocity(x, y)

Useful Scene Properties

javascript
this.cameras.main              // Main camerathis.physics.world             // Physics worldthis.input.keyboard            // Keyboard managerthis.sound                     // Audio managerthis.time                      // Time/clock managerthis.tweens                    // Tween managerthis.anims                     // Animation managerthis.registry                  // Cross-scene data storethis.data                      // Scene-specific data store

Essential Events

javascript
// Scene eventsthis.events.on('pause', callback)this.events.on('resume', callback)this.events.on('shutdown', callback)
// Physics eventsthis.physics.world.on('worldbounds', callback)
// Game object eventssprite.on('destroy', callback)sprite.on('animationcomplete', callback)

See Also

  • references/arcade-physics.md - Deep dive into Arcade physics
  • references/tilemaps.md - Advanced tilemap techniques
  • references/performance.md - Optimization strategies
  • references/spritesheets-nineslice.md - Spritesheet loading (spacing/margin), nine-slice UI panels, asset inspection

Remember

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

Think in systems: What scenes do you need? What entities exist? How do they interact? Answer these questions before writing code, and your game will be maintainable as it grows.

Claude is capable of building complete, polished Phaser games. These guidelines illuminate the path—they don't fence it.

来源与署名

来源:chongdashu/phaserjs-tinyswords位于.claude/skills/phaser-gamedev提交f59f1dc

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架