PixiJS 资源加载 #

Assets 加载器概述 #

PixiJS 8 提供了全新的 Assets 加载器,用于加载和管理各种类型的资源。

text
┌─────────────────────────────────────────────────────────────┐
│                    Assets 加载器                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   支持的资源类型                                            │
│   ├── 图片(PNG, JPG, WebP, SVG)                          │
│   ├── 精灵表(JSON, XML)                                   │
│   ├── 字体(Bitmap Font, Web Font)                        │
│   ├── 音频(MP3, OGG, WAV)                                │
│   ├── 视频                                                 │
│   ├── JSON 数据                                            │
│   └── 纹理                                                 │
│                                                             │
│   核心功能                                                  │
│   ├── 异步加载                                              │
│   ├── 进度回调                                              │
│   ├── 缓存管理                                              │
│   └── 批量加载                                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

基本使用 #

加载单个资源 #

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

// 加载图片
const texture = await Assets.load('images/player.png');

// 创建精灵
const sprite = new PIXI.Sprite(texture);
app.stage.addChild(sprite);

加载多个资源 #

javascript
// 批量加载
const assets = await Assets.load([
  'images/player.png',
  'images/enemy.png',
  'images/background.png'
]);

// 使用加载的资源
const player = new PIXI.Sprite(assets['images/player.png']);
const enemy = new PIXI.Sprite(assets['images/enemy.png']);
const background = new PIXI.Sprite(assets['images/background.png']);

使用别名 #

javascript
// 添加资源清单
Assets.add({
  alias: 'player',
  src: 'images/player.png'
});

Assets.add({
  alias: 'enemy',
  src: 'images/enemy.png'
});

// 使用别名加载
const playerTexture = await Assets.load('player');
const enemyTexture = await Assets.load('enemy');

批量添加资源 #

javascript
// 添加多个资源
Assets.addBundle('game-assets', {
  player: 'images/player.png',
  enemy: 'images/enemy.png',
  background: 'images/background.png',
  'spritesheet': 'sprites/game.json'
});

// 加载整个包
const bundle = await Assets.loadBundle('game-assets');

// 使用资源
const player = new PIXI.Sprite(bundle.player);
const enemy = new PIXI.Sprite(bundle.enemy);

加载进度 #

进度回调 #

javascript
// 监听加载进度
Assets.loadBundle('game-assets', (progress) => {
  console.log(`加载进度: ${progress * 100}%`);
});

自定义加载界面 #

javascript
async function loadWithProgress() {
  const progressBar = new Graphics();
  const progressText = new Text({
    text: '0%',
    style: { fontFamily: 'Arial', fontSize: 24, fill: 0xffffff }
  });
  
  app.stage.addChild(progressBar, progressText);
  
  const bundle = await Assets.loadBundle('game-assets', (progress) => {
    const percent = Math.round(progress * 100);
    
    progressBar.clear();
    progressBar.rect(100, 280, 600 * progress, 40);
    progressBar.fill({ color: 0x00ff00 });
    
    progressText.text = `${percent}%`;
    progressText.x = 400;
    progressText.y = 290;
  });
  
  app.stage.removeChild(progressBar, progressText);
  
  return bundle;
}

加载状态 #

javascript
// 检查资源是否已加载
const isLoaded = Assets.cache.has('player');

// 获取已缓存的资源
const cachedTexture = Assets.cache.get('player');

// 等待资源加载完成
const texture = await Assets.load('player');

图片加载 #

基本图片 #

javascript
// 加载 PNG
const pngTexture = await Assets.load('image.png');

// 加载 JPG
const jpgTexture = await Assets.load('image.jpg');

// 加载 WebP
const webpTexture = await Assets.load('image.webp');

// 加载 SVG
const svgTexture = await Assets.load('image.svg');

带选项加载 #

javascript
const texture = await Assets.load({
  src: 'image.png',
  data: {
    alphaMode: 'premultiply-alpha-on-load',
    resolution: 2,
    scaleMode: 'linear'
  }
});

跨域图片 #

javascript
const texture = await Assets.load({
  src: 'https://example.com/image.png',
  data: {
    crossOrigin: 'anonymous'
  }
});

精灵表加载 #

什么是精灵表 #

text
┌─────────────────────────────────────────────────────────────┐
│                    精灵表结构                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   精灵表图片(atlas.png)                                   │
│   ┌────────────────────────────────────────┐               │
│   │ [frame1] [frame2] [frame3] [frame4]   │               │
│   │ [frame5] [frame6] [frame7] [frame8]   │               │
│   └────────────────────────────────────────┘               │
│                                                             │
│   精灵表数据(atlas.json)                                  │
│   {                                                         │
│     "frames": {                                             │
│       "frame1": { "x": 0, "y": 0, "w": 64, "h": 64 },     │
│       "frame2": { "x": 64, "y": 0, "w": 64, "h": 64 },    │
│       ...                                                   │
│     },                                                      │
│     "meta": { "image": "atlas.png" }                       │
│   }                                                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

加载精灵表 #

javascript
// 加载精灵表
const spritesheet = await Assets.load('sprites/game.json');

// 获取单个帧
const frame1 = spritesheet.textures['frame1.png'];
const sprite1 = new PIXI.Sprite(frame1);

// 获取动画帧序列
const frames = spritesheet.animations['walk'];
const animatedSprite = new PIXI.AnimatedSprite(frames);
animatedSprite.play();

创建精灵表 #

可以使用工具生成精灵表:

工具 说明
TexturePacker 专业工具,功能强大
Shoebox 免费工具
Leshy SpriteSheet Tool 在线工具
PixiJS SpriteSheet Generator 命令行工具

TexturePacker 导出设置 #

text
TexturePacker 设置:
├── Framework: PixiJS
├── Data Format: JSON (Hash)
├── Texture Format: PNG
├── Max Size: 2048x2048
├── Algorithm: MaxRects
└── Trim: Enable(去除透明边缘)

字体加载 #

Web 字体 #

javascript
// 加载 Google Fonts
await Assets.load({
  src: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap',
  data: {
    family: 'Roboto',
    display: 'swap'
  }
});

// 使用字体
const text = new PIXI.Text({
  text: 'Hello Roboto',
  style: {
    fontFamily: 'Roboto',
    fontSize: 36
  }
});

位图字体 #

javascript
// 加载位图字体
await Assets.load('fonts/desycel.xml');

// 使用位图字体
const bitmapText = new PIXI.BitmapText({
  text: 'Hello Bitmap',
  style: {
    fontFamily: 'Desycel',
    fontSize: 48
  }
});

音频加载 #

基本音频 #

javascript
// 加载音频
const sound = await Assets.load('audio/bgm.mp3');

// 播放
sound.play();

// 暂停
sound.pause();

// 停止
sound.stop();

音频选项 #

javascript
const sound = await Assets.load({
  src: 'audio/effect.mp3',
  data: {
    volume: 0.5,
    loop: true,
    speed: 1.0
  }
});

使用 sound 库 #

javascript
// 安装
// npm install @pixi/sound

import { Sound } from '@pixi/sound';

// 加载并播放
const bgm = Sound.from('audio/bgm.mp3');
bgm.play({ loop: true });

// 音效
const effect = Sound.from('audio/effect.mp3');
effect.play();

JSON 数据加载 #

加载 JSON #

javascript
// 加载 JSON 数据
const data = await Assets.load('data/levels.json');

console.log(data.levels);
console.log(data.config);

游戏配置 #

javascript
// 加载游戏配置
const config = await Assets.load('config/game.json');

// 使用配置
const player = new PIXI.Sprite(
  await Assets.load(config.player.sprite)
);
player.speed = config.player.speed;
player.health = config.player.health;

资源管理 #

缓存操作 #

javascript
// 检查缓存
const hasTexture = Assets.cache.has('player');

// 获取缓存
const texture = Assets.cache.get('player');

// 设置缓存
Assets.cache.set('custom-key', texture);

// 删除缓存
Assets.cache.remove('player');

// 清空缓存
Assets.cache.reset();

卸载资源 #

javascript
// 卸载单个资源
Assets.unload('player');

// 卸载多个资源
Assets.unload(['player', 'enemy', 'background']);

// 卸载整个包
Assets.unloadBundle('game-assets');

预加载 #

javascript
// 预加载资源
async function preload() {
  Assets.addBundle('preload', {
    loading: 'images/loading.png',
    logo: 'images/logo.png'
  });
  
  const preloadAssets = await Assets.loadBundle('preload');
  
  // 显示加载界面
  showLoadingScreen(preloadAssets);
  
  // 加载主资源
  Assets.addBundle('main', {
    player: 'images/player.png',
    enemy: 'images/enemy.png'
  });
  
  await Assets.loadBundle('main', onProgress);
  
  // 开始游戏
  startGame();
}

高级用法 #

自定义加载器 #

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

// 创建自定义加载器
class CustomLoader extends Loader {
  async load(url, options) {
    // 自定义加载逻辑
    console.log('自定义加载:', url);
    
    return super.load(url, options);
  }
}

// 注册自定义加载器
Assets.loader = new CustomLoader();

资源依赖 #

javascript
// 加载有依赖的资源
async function loadWithDependencies() {
  // 先加载精灵表图片
  const atlasTexture = await Assets.load('atlas.png');
  
  // 再加载精灵表数据
  const spritesheet = await Assets.load({
    src: 'atlas.json',
    data: {
      texture: atlasTexture
    }
  });
  
  return spritesheet;
}

动态资源 #

javascript
// 根据条件加载不同资源
async function loadPlatformSpecific() {
  const isMobile = /Mobile/.test(navigator.userAgent);
  
  const texture = await Assets.load(
    isMobile ? 'images/player-mobile.png' : 'images/player-desktop.png'
  );
  
  return texture;
}

资源版本控制 #

javascript
// 添加版本号
Assets.add({
  alias: 'player',
  src: 'images/player.png?v=1.0.0'
});

// 或使用配置
const version = '1.0.0';
Assets.addBundle('game-assets', {
  player: `images/player.png?v=${version}`,
  enemy: `images/enemy.png?v=${version}`
});

实战示例 #

游戏资源管理器 #

javascript
class GameAssets {
  constructor() {
    this.loaded = false;
    this.assets = {};
  }
  
  async load(progressCallback) {
    if (this.loaded) return this.assets;
    
    Assets.addBundle('game', {
      // 图片
      player: 'images/player.png',
      enemy: 'images/enemy.png',
      background: 'images/background.png',
      
      // 精灵表
      spritesheet: 'sprites/game.json',
      
      // 字体
      font: 'fonts/game-font.xml',
      
      // 音频
      bgm: 'audio/bgm.mp3',
      effect: 'audio/effect.mp3',
      
      // 数据
      config: 'data/config.json'
    });
    
    this.assets = await Assets.loadBundle('game', progressCallback);
    this.loaded = true;
    
    return this.assets;
  }
  
  get(key) {
    return this.assets[key];
  }
  
  unload() {
    Assets.unloadBundle('game');
    this.loaded = false;
    this.assets = {};
  }
}

const gameAssets = new GameAssets();

// 加载资源
await gameAssets.load((progress) => {
  console.log(`加载中: ${Math.round(progress * 100)}%`);
});

// 使用资源
const player = new PIXI.Sprite(gameAssets.get('player'));

场景资源管理 #

javascript
class SceneAssets {
  constructor(sceneName) {
    this.sceneName = sceneName;
    this.assets = {};
  }
  
  async load() {
    const manifest = await Assets.load(`scenes/${this.sceneName}/manifest.json`);
    
    Assets.addBundle(this.sceneName, manifest.assets);
    
    this.assets = await Assets.loadBundle(this.sceneName);
    
    return this.assets;
  }
  
  unload() {
    Assets.unloadBundle(this.sceneName);
  }
}

// 切换场景时加载/卸载资源
async function changeScene(sceneName) {
  // 卸载当前场景资源
  if (currentSceneAssets) {
    currentSceneAssets.unload();
  }
  
  // 加载新场景资源
  currentSceneAssets = new SceneAssets(sceneName);
  await currentSceneAssets.load();
  
  // 创建场景
  createScene(currentSceneAssets.assets);
}

懒加载 #

javascript
class LazyLoader {
  constructor() {
    this.loaded = new Map();
  }
  
  async get(key, url) {
    if (this.loaded.has(key)) {
      return this.loaded.get(key);
    }
    
    const asset = await Assets.load(url);
    this.loaded.set(key, asset);
    
    return asset;
  }
  
  preload(keys, urls) {
    return Promise.all(
      keys.map((key, i) => this.get(key, urls[i]))
    );
  }
}

const lazyLoader = new LazyLoader();

// 按需加载
const playerTexture = await lazyLoader.get('player', 'images/player.png');

错误处理 #

加载错误 #

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

重试机制 #

javascript
async function loadWithRetry(url, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await Assets.load(url);
    } catch (error) {
      console.log(`重试 ${i + 1}/${maxRetries}`);
      if (i === maxRetries - 1) throw error;
    }
  }
}

超时处理 #

javascript
async function loadWithTimeout(url, timeout = 10000) {
  return Promise.race([
    Assets.load(url),
    new Promise((_, reject) => {
      setTimeout(() => reject(new Error('加载超时')), timeout);
    })
  ]);
}

性能优化 #

资源压缩 #

text
优化建议:
├── 图片压缩
│   ├── 使用 TinyPNG 压缩 PNG
│   ├── 使用 WebP 格式(更小体积)
│   └── 适当降低分辨率
│
├── 精灵表优化
│   ├── 合并小图为精灵表
│   ├── 使用合适的精灵表尺寸
│   └── 去除透明边缘
│
└── 音频优化
    ├── 使用 MP3 格式
    ├── 降低比特率
    └── 裁剪不必要的部分

按需加载 #

javascript
// 分阶段加载
async function loadGame() {
  // 第一阶段:必要资源
  await loadEssentialAssets();
  showMainMenu();
  
  // 第二阶段:游戏资源(后台加载)
  loadGameAssets().then(() => {
    enableStartButton();
  });
  
  // 第三阶段:可选资源
  loadOptionalAssets();
}

内存管理 #

javascript
// 及时卸载不需要的资源
function cleanup() {
  Assets.unload(['temp-image.png', 'old-spritesheet.json']);
}

// 在场景切换时清理
function onSceneChange() {
  cleanup();
  gc();
}

下一步 #

掌握了资源加载后,接下来学习 滤镜效果,了解如何使用滤镜创建炫酷的视觉效果!

最后更新:2026-03-29