Phaser 高级主题 #

项目架构 #

目录结构 #

text
my-phaser-game/
├── src/
│   ├── main.js              # 游戏入口
│   ├── config.js            # 游戏配置
│   ├── scenes/              # 场景目录
│   │   ├── BootScene.js
│   │   ├── PreloadScene.js
│   │   ├── MenuScene.js
│   │   ├── GameScene.js
│   │   └── UIScene.js
│   ├── objects/             # 游戏对象
│   │   ├── Player.js
│   │   ├── Enemy.js
│   │   └── Item.js
│   ├── components/          # UI 组件
│   │   ├── Button.js
│   │   ├── HealthBar.js
│   │   └── ScoreDisplay.js
│   ├── managers/            # 管理器
│   │   ├── AudioManager.js
│   │   ├── DataManager.js
│   │   └── InputManager.js
│   ├── plugins/             # 插件
│   │   └── CustomPlugin.js
│   ├── utils/               # 工具函数
│   │   ├── math.js
│   │   └── storage.js
│   └── constants/           # 常量
│       └── game.js
├── assets/
│   ├── images/
│   ├── sprites/
│   ├── audio/
│   └── fonts/
├── public/
├── index.html
├── package.json
└── vite.config.js

配置管理 #

javascript
const config = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  parent: 'game-container',
  backgroundColor: '#2d2d2d',
  scale: {
    mode: Phaser.Scale.FIT,
    autoCenter: Phaser.Scale.CENTER_BOTH
  },
  physics: {
    default: 'arcade',
    arcade: {
      gravity: { y: 300 },
      debug: false
    }
  },
  render: {
    pixelArt: true,
    antialias: false
  },
  scene: [BootScene, PreloadScene, MenuScene, GameScene, UIScene]
};

export default config;

游戏入口 #

javascript
import Phaser from 'phaser';
import config from './config';

class Game extends Phaser.Game {
  constructor() {
    super(config);
  }
}

window.addEventListener('load', () => {
  new Game();
});

设计模式 #

单例模式 #

javascript
class GameManager {
  static instance = null;
  
  constructor() {
    if (GameManager.instance) {
      return GameManager.instance;
    }
    
    this.score = 0;
    this.level = 1;
    this.lives = 3;
    
    GameManager.instance = this;
  }
  
  static getInstance() {
    if (!GameManager.instance) {
      GameManager.instance = new GameManager();
    }
    return GameManager.instance;
  }
  
  reset() {
    this.score = 0;
    this.level = 1;
    this.lives = 3;
  }
}

const gameManager = GameManager.getInstance();

工厂模式 #

javascript
class GameObjectFactory {
  constructor(scene) {
    this.scene = scene;
  }
  
  create(type, x, y, config = {}) {
    switch (type) {
      case 'player':
        return new Player(this.scene, x, y, config);
      case 'enemy':
        return new Enemy(this.scene, x, y, config);
      case 'item':
        return new Item(this.scene, x, y, config);
      default:
        throw new Error(`Unknown object type: ${type}`);
    }
  }
}

class GameScene extends Phaser.Scene {
  create() {
    this.factory = new GameObjectFactory(this);
    
    this.player = this.factory.create('player', 100, 100);
    this.enemy = this.factory.create('enemy', 300, 100, { speed: 150 });
  }
}

观察者模式 #

javascript
class EventEmitter {
  constructor() {
    this.events = {};
  }
  
  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
    return () => this.off(event, callback);
  }
  
  off(event, callback) {
    if (!this.events[event]) return;
    this.events[event] = this.events[event].filter(cb => cb !== callback);
  }
  
  emit(event, ...args) {
    if (!this.events[event]) return;
    this.events[event].forEach(callback => callback(...args));
  }
}

class GameEvents extends EventEmitter {
  static SCORE_UPDATE = 'scoreUpdate';
  static GAME_OVER = 'gameOver';
  static LEVEL_COMPLETE = 'levelComplete';
}

const gameEvents = new GameEvents();

gameEvents.on(GameEvents.SCORE_UPDATE, (score) => {
  console.log('Score:', score);
});

gameEvents.emit(GameEvents.SCORE_UPDATE, 100);

状态模式 #

javascript
class PlayerState {
  constructor(player) {
    this.player = player;
  }
  
  enter() {}
  exit() {}
  update() {}
}

class IdleState extends PlayerState {
  enter() {
    this.player.setVelocity(0, 0);
    this.player.anims.play('idle');
  }
  
  update(cursors) {
    if (cursors.left.isDown || cursors.right.isDown) {
      this.player.setState('walk');
    }
    if (cursors.up.isDown && this.player.body.blocked.down) {
      this.player.setState('jump');
    }
  }
}

class WalkState extends PlayerState {
  enter() {
    this.player.anims.play('walk');
  }
  
  update(cursors) {
    if (cursors.left.isDown) {
      this.player.setVelocityX(-160);
      this.player.setFlipX(true);
    } else if (cursors.right.isDown) {
      this.player.setVelocityX(160);
      this.player.setFlipX(false);
    } else {
      this.player.setState('idle');
    }
    
    if (cursors.up.isDown && this.player.body.blocked.down) {
      this.player.setState('jump');
    }
  }
}

class JumpState extends PlayerState {
  enter() {
    this.player.setVelocityY(-330);
    this.player.anims.play('jump');
  }
  
  update(cursors) {
    if (cursors.left.isDown) {
      this.player.setVelocityX(-160);
    } else if (cursors.right.isDown) {
      this.player.setVelocityX(160);
    }
    
    if (this.player.body.blocked.down) {
      this.player.setState('idle');
    }
  }
}

class Player extends Phaser.Physics.Arcade.Sprite {
  constructor(scene, x, y) {
    super(scene, x, y, 'player');
    
    scene.add.existing(this);
    scene.physics.add.existing(this);
    
    this.states = {
      idle: new IdleState(this),
      walk: new WalkState(this),
      jump: new JumpState(this)
    };
    
    this.currentState = this.states.idle;
    this.currentState.enter();
  }
  
  setState(stateName) {
    this.currentState.exit();
    this.currentState = this.states[stateName];
    this.currentState.enter();
  }
  
  update(cursors) {
    this.currentState.update(cursors);
  }
}

数据管理 #

本地存储 #

javascript
class StorageManager {
  constructor(prefix = 'game_') {
    this.prefix = prefix;
  }
  
  save(key, value) {
    try {
      localStorage.setItem(this.prefix + key, JSON.stringify(value));
      return true;
    } catch (e) {
      console.error('Failed to save:', e);
      return false;
    }
  }
  
  load(key, defaultValue = null) {
    try {
      const value = localStorage.getItem(this.prefix + key);
      return value ? JSON.parse(value) : defaultValue;
    } catch (e) {
      console.error('Failed to load:', e);
      return defaultValue;
    }
  }
  
  remove(key) {
    localStorage.removeItem(this.prefix + key);
  }
  
  clear() {
    Object.keys(localStorage)
      .filter(key => key.startsWith(this.prefix))
      .forEach(key => localStorage.removeItem(key));
  }
}

const storage = new StorageManager();

storage.save('highScore', 1000);
const highScore = storage.load('highScore', 0);

游戏存档 #

javascript
class SaveManager {
  constructor() {
    this.storage = new StorageManager('save_');
  }
  
  saveGame(state) {
    const saveData = {
      timestamp: Date.now(),
      player: {
        x: state.player.x,
        y: state.player.y,
        health: state.player.health,
        score: state.player.score
      },
      level: state.level,
      inventory: state.inventory
    };
    
    return this.storage.save('gameState', saveData);
  }
  
  loadGame() {
    return this.storage.load('gameState');
  }
  
  hasSave() {
    return this.storage.load('gameState') !== null;
  }
  
  deleteSave() {
    this.storage.remove('gameState');
  }
}

发布部署 #

构建配置 #

javascript
import { defineConfig } from 'vite';

export default defineConfig({
  base: './',
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true
      }
    },
    rollupOptions: {
      output: {
        assetFileNames: 'assets/[name].[ext]',
        chunkFileNames: 'js/[name].[hash].js',
        entryFileNames: 'js/[name].[hash].js'
      }
    }
  },
  server: {
    open: true,
    port: 3000
  }
});

打包命令 #

json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

部署到 Web 服务器 #

bash
npm run build

scp -r dist/* user@server:/var/www/game/

部署到 CDN #

javascript
const config = {
  loader: {
    baseURL: 'https://cdn.example.com/game/'
  }
};

调试技巧 #

开发模式检测 #

javascript
const isDev = import.meta.env.DEV;

if (isDev) {
  this.physics.world.createDebugGraphic();
}

错误处理 #

javascript
window.onerror = function(message, source, lineno, colno, error) {
  console.error('Error:', message, source, lineno, colno, error);
  return false;
};

window.addEventListener('unhandledrejection', function(event) {
  console.error('Unhandled rejection:', event.reason);
});

日志系统 #

javascript
class Logger {
  constructor(enabled = true) {
    this.enabled = enabled;
  }
  
  log(...args) {
    if (this.enabled) console.log('[LOG]', ...args);
  }
  
  warn(...args) {
    if (this.enabled) console.warn('[WARN]', ...args);
  }
  
  error(...args) {
    console.error('[ERROR]', ...args);
  }
  
  time(label) {
    if (this.enabled) console.time(label);
  }
  
  timeEnd(label) {
    if (this.enabled) console.timeEnd(label);
  }
}

const logger = new Logger(import.meta.env.DEV);

完整示例 #

游戏管理器 #

javascript
class Game {
  constructor() {
    this.config = this.createConfig();
    this.game = new Phaser.Game(this.config);
    this.setupGlobalEvents();
  }
  
  createConfig() {
    return {
      type: Phaser.AUTO,
      width: 800,
      height: 600,
      parent: 'game-container',
      backgroundColor: '#2d2d2d',
      scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Phaser.Scale.CENTER_BOTH
      },
      physics: {
        default: 'arcade',
        arcade: {
          gravity: { y: 300 },
          debug: false
        }
      },
      scene: [BootScene, PreloadScene, MenuScene, GameScene, UIScene]
    };
  }
  
  setupGlobalEvents() {
    this.game.events.on('ready', () => {
      console.log('Game ready');
    });
  }
}

window.addEventListener('load', () => {
  new Game();
});

总结 #

恭喜你完成了 Phaser 完全指南的学习!你现在应该已经掌握了:

  1. Phaser 的基本概念和安装配置
  2. 场景系统和游戏对象
  3. 精灵系统和动画
  4. 输入处理和物理引擎
  5. 瓦片地图和音频系统
  6. 补间动画和粒子效果
  7. 游戏组和插件系统
  8. 着色器和性能优化
  9. 项目架构和最佳实践

继续实践,创建你自己的游戏!

最后更新:2026-03-29