PixiJS 高级主题 #

性能优化概述 #

性能优化是 PixiJS 开发中的重要环节,良好的优化可以让应用在各种设备上流畅运行。

text
┌─────────────────────────────────────────────────────────────┐
│                    性能优化方向                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   渲染优化                                                  │
│   ├── 减少绘制调用                                          │
│   ├── 使用批处理                                            │
│   ├── 合理使用缓存                                          │
│   └── 优化滤镜                                              │
│                                                             │
│   内存优化                                                  │
│   ├── 纹理管理                                              │
│   ├── 对象池                                                │
│   ├── 及时销毁                                              │
│   └── 避免内存泄漏                                          │
│                                                             │
│   更新优化                                                  │
│   ├── 减少更新频率                                          │
│   ├── 空间分区                                              │
│   ├── 视口裁剪                                              │
│   └── LOD(细节层次)                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

渲染优化 #

批处理渲染 #

PixiJS 会自动批处理相同纹理的精灵:

javascript
// 好:相同纹理,自动批处理
const texture = PIXI.Texture.from('particle.png');
for (let i = 0; i < 1000; i++) {
  const sprite = new PIXI.Sprite(texture);
  app.stage.addChild(sprite);
}

// 差:不同纹理,无法批处理
for (let i = 0; i < 1000; i++) {
  const sprite = PIXI.Sprite.from(`particle_${i % 10}.png`);
  app.stage.addChild(sprite);
}

使用精灵表 #

javascript
// 使用精灵表可以让多个精灵共享同一纹理
const spritesheet = await Assets.load('sprites.json');

// 这些精灵可以批处理
const sprites = [];
for (let i = 0; i < 100; i++) {
  const sprite = new PIXI.Sprite(spritesheet.textures['particle.png']);
  sprites.push(sprite);
  app.stage.addChild(sprite);
}

ParticleContainer #

对于大量粒子,使用 ParticleContainer:

javascript
import { ParticleContainer } from 'pixi.js';

const particleContainer = new ParticleContainer(10000, {
  scale: true,
  position: true,
  rotation: true,
  uvs: true,
  alpha: true
});

app.stage.addChild(particleContainer);

// 添加粒子
for (let i = 0; i < 10000; i++) {
  const particle = PIXI.Sprite.from('particle.png');
  particleContainer.addChild(particle);
}

缓存位图 #

javascript
// 对于复杂的静态内容,启用缓存
const complexContainer = new Container();

// 添加多个子对象...
complexContainer.addChild(/* ... */);

// 缓存为位图
complexContainer.cacheAsBitmap = true;

// 更新时需要重新缓存
complexContainer.cacheAsBitmap = false;
// 更新内容...
complexContainer.cacheAsBitmap = true;

渲染纹理 #

javascript
import { RenderTexture } from 'pixi.js';

// 创建渲染纹理
const renderTexture = RenderTexture.create({
  width: 512,
  height: 512
});

// 渲染到纹理
app.renderer.render({
  container: complexGraphics,
  target: renderTexture
});

// 使用渲染结果
const sprite = new PIXI.Sprite(renderTexture);

内存管理 #

纹理管理 #

javascript
// 销毁纹理
texture.destroy(true);

// 从缓存移除
PIXI.Texture.removeFromCache('texture-id');

// 清理纹理缓存
PIXI.utils.clearTextureCache();

销毁显示对象 #

javascript
// 销毁精灵
sprite.destroy();

// 销毁并清理纹理
sprite.destroy({
  children: true,      // 销毁子对象
  texture: true,       // 销毁纹理
  textureSource: true, // 销毁纹理源
  context: true        // 销毁 WebGL 上下文
});

// 销毁容器
container.destroy({
  children: true
});

销毁应用 #

javascript
// 完整销毁应用
app.destroy(true, {
  children: true,
  texture: true,
  textureSource: true,
  context: true
});

对象池 #

javascript
class ObjectPool {
  constructor(createFn, resetFn, initialSize = 10) {
    this.createFn = createFn;
    this.resetFn = resetFn;
    this.pool = [];
    
    for (let i = 0; i < initialSize; i++) {
      this.pool.push(this.create());
    }
  }
  
  create() {
    const obj = this.createFn();
    obj._pooled = true;
    return obj;
  }
  
  get() {
    if (this.pool.length > 0) {
      const obj = this.pool.pop();
      this.resetFn(obj);
      return obj;
    }
    return this.create();
  }
  
  release(obj) {
    if (obj._pooled) {
      this.pool.push(obj);
    }
  }
}

// 使用对象池
const bulletPool = new ObjectPool(
  () => {
    const bullet = PIXI.Sprite.from('bullet.png');
    bullet.visible = false;
    app.stage.addChild(bullet);
    return bullet;
  },
  (bullet) => {
    bullet.visible = false;
    bullet.x = 0;
    bullet.y = 0;
  },
  50
);

// 获取子弹
const bullet = bulletPool.get();
bullet.visible = true;
bullet.x = player.x;
bullet.y = player.y;

// 释放子弹
bulletPool.release(bullet);

内存泄漏检测 #

javascript
// 检测显示对象数量
function countDisplayObjects(container) {
  let count = 0;
  
  const traverse = (obj) => {
    count++;
    if (obj.children) {
      obj.children.forEach(traverse);
    }
  };
  
  traverse(container);
  return count;
}

// 定期检查
setInterval(() => {
  console.log('显示对象数量:', countDisplayObjects(app.stage));
}, 5000);

更新优化 #

视口裁剪 #

javascript
class ViewportCulling {
  constructor(app) {
    this.app = app;
    this.visibleObjects = new Set();
  }
  
  update(objects) {
    const screen = this.app.screen;
    
    objects.forEach(obj => {
      const bounds = obj.getBounds();
      
      const isVisible = 
        bounds.x < screen.width &&
        bounds.x + bounds.width > 0 &&
        bounds.y < screen.height &&
        bounds.y + bounds.height > 0;
      
      obj.visible = isVisible;
    });
  }
}

空间分区 #

javascript
class SpatialHash {
  constructor(cellSize) {
    this.cellSize = cellSize;
    this.grid = new Map();
  }
  
  getKey(x, y) {
    const cellX = Math.floor(x / this.cellSize);
    const cellY = Math.floor(y / this.cellSize);
    return `${cellX},${cellY}`;
  }
  
  insert(obj) {
    const key = this.getKey(obj.x, obj.y);
    
    if (!this.grid.has(key)) {
      this.grid.set(key, []);
    }
    
    this.grid.get(key).push(obj);
  }
  
  query(x, y, radius) {
    const results = [];
    const minCellX = Math.floor((x - radius) / this.cellSize);
    const maxCellX = Math.floor((x + radius) / this.cellSize);
    const minCellY = Math.floor((y - radius) / this.cellSize);
    const maxCellY = Math.floor((y + radius) / this.cellSize);
    
    for (let cx = minCellX; cx <= maxCellX; cx++) {
      for (let cy = minCellY; cy <= maxCellY; cy++) {
        const key = `${cx},${cy}`;
        const cell = this.grid.get(key);
        
        if (cell) {
          results.push(...cell);
        }
      }
    }
    
    return results;
  }
  
  clear() {
    this.grid.clear();
  }
}

LOD(细节层次) #

javascript
class LODSystem {
  constructor() {
    this.levels = [];
  }
  
  addLevel(distance, createFn) {
    this.levels.push({ distance, createFn });
    this.levels.sort((a, b) => a.distance - b.distance);
  }
  
  update(camera, objects) {
    objects.forEach(obj => {
      const dist = this.getDistance(camera, obj);
      
      for (let i = this.levels.length - 1; i >= 0; i--) {
        if (dist >= this.levels[i].distance) {
          this.setLevel(obj, i);
          break;
        }
      }
    });
  }
  
  getDistance(camera, obj) {
    return Math.hypot(camera.x - obj.x, camera.y - obj.y);
  }
  
  setLevel(obj, level) {
    if (obj.currentLOD !== level) {
      obj.currentLOD = level;
      // 更新显示对象
    }
  }
}

调试技巧 #

FPS 显示 #

javascript
class FPSCounter {
  constructor() {
    this.fps = 0;
    this.frames = 0;
    this.lastTime = performance.now();
    
    this.text = new Text({
      text: 'FPS: 0',
      style: {
        fontFamily: 'monospace',
        fontSize: 16,
        fill: 0x00ff00
      }
    });
  }
  
  update() {
    this.frames++;
    const now = performance.now();
    
    if (now - this.lastTime >= 1000) {
      this.fps = this.frames;
      this.frames = 0;
      this.lastTime = now;
      
      this.text.text = `FPS: ${this.fps}`;
    }
  }
}

const fpsCounter = new FPSCounter();
app.stage.addChild(fpsCounter.text);

app.ticker.add(() => {
  fpsCounter.update();
});

渲染统计 #

javascript
class RenderStats {
  constructor(app) {
    this.app = app;
    this.stats = {
      drawCalls: 0,
      objectsRendered: 0
    };
    
    this.text = new Text({
      text: '',
      style: {
        fontFamily: 'monospace',
        fontSize: 14,
        fill: 0xffffff
      }
    });
    
    this.setupHooks();
  }
  
  setupHooks() {
    this.app.renderer.on('prerender', () => {
      this.stats.drawCalls = 0;
      this.stats.objectsRendered = 0;
    });
    
    this.app.renderer.on('postrender', () => {
      this.updateText();
    });
  }
  
  updateText() {
    this.text.text = [
      `Draw Calls: ${this.stats.drawCalls}`,
      `Objects: ${this.stats.objectsRendered}`
    ].join('\n');
  }
}

性能分析 #

javascript
class PerformanceProfiler {
  constructor() {
    this.profiles = new Map();
  }
  
  start(name) {
    this.profiles.set(name, {
      start: performance.now(),
      calls: 0,
      total: 0
    });
  }
  
  end(name) {
    const profile = this.profiles.get(name);
    if (profile) {
      profile.calls++;
      profile.total += performance.now() - profile.start;
    }
  }
  
  getReport() {
    const report = [];
    
    this.profiles.forEach((profile, name) => {
      report.push({
        name,
        calls: profile.calls,
        total: profile.total.toFixed(2),
        average: (profile.total / profile.calls).toFixed(2)
      });
    });
    
    return report;
  }
}

const profiler = new PerformanceProfiler();

// 使用
app.ticker.add(() => {
  profiler.start('update');
  update();
  profiler.end('update');
  
  profiler.start('render');
  // 渲染逻辑
  profiler.end('render');
});

调试工具 #

javascript
// 启用 PixiJS DevTools
if (import.meta.env.DEV) {
  globalThis.__PIXI_APP__ = app;
  globalThis.__PIXI_STAGE__ = app.stage;
  globalThis.__PIXI_RENDERER__ = app.renderer;
}

// 显示边界框
function showBounds(displayObject, color = 0xff0000) {
  const bounds = displayObject.getBounds();
  
  const graphics = new Graphics();
  graphics.rect(bounds.x, bounds.y, bounds.width, bounds.height);
  graphics.stroke({ width: 1, color });
  
  app.stage.addChild(graphics);
  
  return graphics;
}

// 显示锚点
function showAnchor(sprite, color = 0x00ff00) {
  const graphics = new Graphics();
  graphics.circle(sprite.x, sprite.y, 5);
  graphics.fill({ color });
  
  app.stage.addChild(graphics);
  
  return graphics;
}

架构设计 #

场景管理 #

javascript
class SceneManager {
  constructor(app) {
    this.app = app;
    this.scenes = new Map();
    this.currentScene = null;
  }
  
  add(name, scene) {
    this.scenes.set(name, scene);
  }
  
  async switchTo(name) {
    if (this.currentScene) {
      await this.currentScene.onExit();
      this.app.stage.removeChild(this.currentScene);
    }
    
    const scene = this.scenes.get(name);
    
    if (scene) {
      this.currentScene = scene;
      this.app.stage.addChild(scene);
      await scene.onEnter();
    }
  }
  
  update(delta) {
    if (this.currentScene) {
      this.currentScene.update(delta);
    }
  }
}

class Scene extends Container {
  async onEnter() {
    // 进入场景
  }
  
  async onExit() {
    // 离开场景
  }
  
  update(delta) {
    // 更新逻辑
  }
}

实体组件系统 #

javascript
class Entity {
  constructor() {
    this.components = new Map();
  }
  
  addComponent(component) {
    this.components.set(component.constructor, component);
    component.entity = this;
    component.init();
    return this;
  }
  
  getComponent(ComponentClass) {
    return this.components.get(ComponentClass);
  }
  
  removeComponent(ComponentClass) {
    const component = this.components.get(ComponentClass);
    if (component) {
      component.destroy();
      this.components.delete(ComponentClass);
    }
    return this;
  }
  
  update(delta) {
    this.components.forEach(component => {
      component.update(delta);
    });
  }
}

class Component {
  constructor() {
    this.entity = null;
  }
  
  init() {}
  
  update(delta) {}
  
  destroy() {}
}

// 示例组件
class TransformComponent extends Component {
  constructor(x = 0, y = 0) {
    super();
    this.x = x;
    this.y = y;
    this.rotation = 0;
    this.scale = { x: 1, y: 1 };
  }
}

class SpriteComponent extends Component {
  constructor(texture) {
    super();
    this.sprite = new PIXI.Sprite(texture);
  }
  
  init() {
    const transform = this.entity.getComponent(TransformComponent);
    if (transform) {
      this.sprite.x = transform.x;
      this.sprite.y = transform.y;
    }
  }
  
  update(delta) {
    const transform = this.entity.getComponent(TransformComponent);
    if (transform) {
      this.sprite.x = transform.x;
      this.sprite.y = transform.y;
      this.sprite.rotation = transform.rotation;
    }
  }
}

// 使用
const player = new Entity()
  .addComponent(new TransformComponent(100, 100))
  .addComponent(new SpriteComponent(texture));

状态机 #

javascript
class StateMachine {
  constructor() {
    this.states = new Map();
    this.currentState = null;
  }
  
  addState(name, state) {
    this.states.set(name, state);
    state.machine = this;
  }
  
  setState(name) {
    const newState = this.states.get(name);
    
    if (newState && newState !== this.currentState) {
      if (this.currentState) {
        this.currentState.onExit();
      }
      
      this.currentState = newState;
      this.currentState.onEnter();
    }
  }
  
  update(delta) {
    if (this.currentState) {
      this.currentState.update(delta);
    }
  }
}

class State {
  constructor() {
    this.machine = null;
  }
  
  onEnter() {}
  
  onExit() {}
  
  update(delta) {}
}

// 示例:角色状态
class IdleState extends State {
  onEnter() {
    console.log('进入空闲状态');
  }
  
  update(delta) {
    // 检查是否应该切换到其他状态
    if (this.isMoving) {
      this.machine.setState('walk');
    }
  }
  
  onExit() {
    console.log('离开空闲状态');
  }
}

class WalkState extends State {
  onEnter() {
    console.log('进入行走状态');
  }
  
  update(delta) {
    if (!this.isMoving) {
      this.machine.setState('idle');
    }
  }
}

最佳实践 #

代码组织 #

text
项目结构建议:
├── src/
│   ├── main.js           # 入口文件
│   ├── config.js         # 配置文件
│   ├── scenes/           # 场景
│   │   ├── MenuScene.js
│   │   └── GameScene.js
│   ├── entities/         # 实体
│   │   ├── Player.js
│   │   └── Enemy.js
│   ├── components/       # 组件
│   │   ├── Sprite.js
│   │   └── Physics.js
│   ├── systems/          # 系统
│   │   ├── Input.js
│   │   └── Collision.js
│   ├── utils/            # 工具
│   │   ├── math.js
│   │   └── pool.js
│   └── assets/           # 资源配置
│       └── manifest.js

资源管理 #

javascript
// 资源清单
const assetManifest = {
  bundles: [
    {
      name: 'preload',
      assets: [
        { alias: 'loading', src: 'images/loading.png' }
      ]
    },
    {
      name: 'game',
      assets: [
        { alias: 'player', src: 'images/player.png' },
        { alias: 'enemy', src: 'images/enemy.png' },
        { alias: 'spritesheet', src: 'sprites/game.json' }
      ]
    }
  ]
};

// 加载资源
async function loadAssets() {
  await Assets.init({ manifest: assetManifest });
  
  const preload = await Assets.loadBundle('preload');
  showLoadingScreen(preload);
  
  await Assets.loadBundle('game', onProgress);
}

响应式设计 #

javascript
function setupResponsive(app) {
  const resize = () => {
    const width = window.innerWidth;
    const height = window.innerHeight;
    
    app.renderer.resize(width, height);
    
    // 更新游戏内容
    updateGameLayout(width, height);
  };
  
  window.addEventListener('resize', resize);
  resize();
}

错误处理 #

javascript
// 全局错误处理
window.onerror = (message, source, lineno, colno, error) => {
  console.error('全局错误:', message);
  // 上报错误
};

// Promise 错误
window.onunhandledrejection = (event) => {
  console.error('未处理的 Promise 错误:', event.reason);
};

// 资源加载错误
try {
  const texture = await Assets.load('image.png');
} catch (error) {
  console.error('资源加载失败:', error);
  // 使用默认资源
}

无障碍访问 #

javascript
// 添加 ARIA 标签
const button = new Container();
button.accessible = true;
button.accessibleTitle = '开始游戏';
button.accessibleHint = '点击开始新游戏';

// 键盘导航
button.eventMode = 'static';
button.on('keydown', (event) => {
  if (event.key === 'Enter' || event.key === ' ') {
    button.emit('click');
  }
});

总结 #

恭喜你完成了 PixiJS 完全指南的学习!你已经掌握了:

  1. 基础概念:Application、Container、DisplayObject
  2. 图形绘制:Graphics API 绘制各种形状
  3. 文本处理:Text 和 BitmapText 的使用
  4. 交互事件:鼠标、触摸、键盘事件处理
  5. 动画系统:Ticker 和 Tween 动画
  6. 资源加载:Assets 加载器的使用
  7. 滤镜效果:内置和扩展滤镜
  8. 高级主题:性能优化、架构设计

继续实践,探索更多 PixiJS 的可能性!

最后更新:2026-03-29