mcpField
L
loading-assets

loading-assets

github.com/phaserjs开发40.6k927 次安装10 周前更新
代码仓库

关于 loading-assets

面向 Phaser 游戏开发者的资源加载技能指南,介绍如何使用 Loader 在场景中排队加载资源。涵盖多种文件类型、全局缓存和加载进度事件。

主要功能

  1. 01加载图像、音频和视频
  2. 02加载数据、字体与地图
  3. 03通过资源包组织文件
  4. 04使用全局缓存共享资源
  5. 05监听加载进度与错误事件

适用场景

  1. 01在场景启动前加载游戏资源
  2. 02制作资源加载进度条
  3. 03按清单加载一组资源
  4. 04根据加载结果处理失败文件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/phaserjs/phaser --skill loading-assets

安装后在 Claude Code 中输入/loading-assets确认已加载。

附带文件references/REFERENCE.md

详细介绍

加载资源

Phaser 加载器(this.load)负责获取所有外部内容:图片、音频、JSON、瓦片地图、图集、字体、脚本等。资源在 preload() 中排队,并行加载,并放入全局缓存中,供每个 Scene 访问。

关键源码路径: src/loader/LoaderPlugin.js、src/loader/File.js、src/loader/filetypes/、src/loader/events/ 相关技能: ../game-setup-and-config/SKILL.md、../scenes/SKILL.md、../sprites-and-images/SKILL.md

快速开始

class GameScene extends Phaser.Scene {
    preload() {
        this.load.image('logo', 'assets/logo.png');
    }

    create() {
        this.add.image(400, 300, 'logo');
    }
}

在 preload() 中加载的资源,在 create() 运行时保证已就绪。加载器会在 preload 阶段自动启动。

核心概念

Preload 模式

每个 Scene 都可以定义一个 preload() 方法。当 preload() 完成时,加载器会自动启动,并等待所有排队的文件完成后才调用 create()。

preload() {
    // Queue files - they don't load immediately
    this.load.image('sky', 'assets/sky.png');
    this.load.spritesheet('dude', 'assets/dude.png', { frameWidth: 32, frameHeight: 48 });
    this.load.audio('jump', 'assets/jump.mp3');
}

create() {
    // All assets above are now available
    this.add.image(400, 300, 'sky');
    this.add.sprite(100, 450, 'dude');
    this.sound.play('jump');
}
在 Preload 之外加载

如果你在 preload() 之外调用 this.load 方法(例如在 create() 中或响应用户操作时),必须手动启动加载器:

create() {
    this.load.image('extra', 'assets/extra.png');
    this.load.once('complete', () => {
        this.add.image(400, 300, 'extra');
    });
    this.load.start();
}
URL 解析:baseURL、path 和 prefix

文件的最终 URL 按如下方式解析:baseURL + path + filename。这些可以通过游戏配置或运行时设置。

preload() {
    // Set base URL (prepended to all relative paths)
    this.load.setBaseURL('https://cdn.example.com/');

    // Set path (prepended after baseURL, before filename)
    this.load.setPath('assets/images/');

    // Set key prefix (prepended to the cache key, not the URL)
    this.load.setPrefix('LEVEL1.');

    // Loads from: https://cdn.example.com/assets/images/hero.png
    // Cached with key: LEVEL1.hero
    this.load.image('hero', 'hero.png');

    // Absolute URLs bypass the path/baseURL
    this.load.image('cloud', 'https://other-server.com/cloud.png');
}

这些也可以在游戏配置中设置:

const config = {
    loader: {
        baseURL: 'https://cdn.example.com/',
        path: 'assets/',
        prefix: '',
        maxParallelDownloads: 32,
        crossOrigin: 'anonymous',
        responseType: '',
        async: true,
        timeout: 0,
        maxRetries: 2,
        imageLoadType: 'XHR' // or 'HTMLImageElement'
    }
};
全局缓存

资源存储在游戏级别的全局缓存中,而不是每个 Scene 各自存储。在一个 Scene 中加载的图片,在其他每个 Scene 中都可使用。纹理放入 game.textures(纹理管理器)。其他数据放入 game.cache 的子缓存中(例如 game.cache.json、game.cache.audio、game.cache.xml)。

加载事件

加载器在整个加载生命周期中会发出事件。使用这些事件来实现进度条和加载界面。

preload() {
    this.load.on('progress', (value) => {
        // value is 0 to 1
        console.log(`Loading: ${Math.round(value * 100)}%`);
    });

    this.load.on('complete', () => {
        console.log('All assets loaded');
    });

    this.load.on('loaderror', (file) => {
        console.warn('Failed to load:', file.key);
    });

    this.load.image('bg', 'assets/bg.png');
}

常见模式

加载图片和精灵图集
preload() {
    // Single image
    this.load.image('star', 'assets/star.png');

    // Image with normal map (pass URL array: [texture, normalMap])
    this.load.image('brick', ['assets/brick.png', 'assets/brick_n.png']);

    // Sprite sheet (fixed frame sizes)
    this.load.spritesheet('explosion', 'assets/explosion.png', {
        frameWidth: 64,
        frameHeight: 64,
        startFrame: 0,
        endFrame: 23,
        margin: 0,
        spacing: 0
    });

    // SVG (optionally rasterize at a specific size)
    this.load.svg('logo', 'assets/logo.svg', { width: 400, height: 400 });
}
加载音频
preload() {
    // Single file
    this.load.audio('bgm', 'assets/music.mp3');

    // Multiple formats for cross-browser support
    this.load.audio('bgm', ['assets/music.ogg', 'assets/music.mp3']);

    // Audio sprite (JSON defines named regions within a single audio file)
    this.load.audioSprite('sfx', 'assets/sfx.json', [
        'assets/sfx.ogg',
        'assets/sfx.mp3'
    ]);
}
加载 JSON 和瓦片地图
preload() {
    // JSON data (stored in this.cache.json)
    this.load.json('levelData', 'assets/level1.json');

    // JSON with a dataKey to extract a sub-object
    this.load.json('enemies', 'assets/data.json', 'enemies');

    // Tiled tilemap (JSON format exported from Tiled)
    this.load.tilemapTiledJSON('map', 'assets/map.json');

    // CSV tilemap
    this.load.tilemapCSV('csvmap', 'assets/level.csv');

    // Impact tilemap
    this.load.tilemapImpact('impactmap', 'assets/level.js');
}

create() {
    const data = this.cache.json.get('levelData');
    const map = this.make.tilemap({ key: 'map' });
}
加载图集
preload() {
    // JSON atlas (e.g., TexturePacker JSON Hash/Array)
    this.load.atlas('sprites', 'assets/sprites.png', 'assets/sprites.json');

    // XML atlas (e.g., Starling/Sparrow format)
    this.load.atlasXML('ui', 'assets/ui.png', 'assets/ui.xml');

    // Multi-atlas (atlas split across multiple textures)
    this.load.multiatlas('world', 'assets/world.json', 'assets/');

    // Unity texture atlas format
    this.load.unityAtlas('chars', 'assets/chars.png', 'assets/chars.txt');

    // Aseprite atlas
    this.load.aseprite('knight', 'assets/knight.png', 'assets/knight.json');
}

create() {
    this.add.sprite(400, 300, 'sprites', 'walk_01');
}
加载位图字体
preload() {
    // Requires both a texture and XML/JSON font data file
    this.load.bitmapFont('pixels', 'assets/font.png', 'assets/font.xml');
}

create() {
    this.add.bitmapText(100, 100, 'pixels', 'Hello World', 32);
}
加载视频
preload() {
    // Load a video file. Third arg: noAudio flag (default false)
    this.load.video('intro', 'assets/intro.mp4');

    // Load without audio track
    this.load.video('bg_loop', 'assets/loop.mp4', true);
}
加载 Web 字体
preload() {
    // Load a font file (ttf, otf, woff, woff2)
    this.load.font('myFont', 'assets/myfont.ttf', 'truetype');

    // With optional font face descriptors
    this.load.font('boldFont', 'assets/bold.woff2', 'woff2', {
        weight: 'bold',
        style: 'normal'
    });
}
加载 Pack 文件

Pack 文件是一个 JSON 文件,描述了一次性加载的多个资源。适合用于组织资源清单。

preload() {
    this.load.pack('pack1', 'assets/pack.json');
}

Pack 文件格式:

{
    "section1": {
        "baseURL": "assets/",
        "files": [
            { "type": "image", "key": "bg", "url": "bg.png" },
            { "type": "atlas", "key": "chars", "textureURL": "chars.png", "atlasURL": "chars.json" }
        ]
    }
}
配合进度条加载
preload() {
    const progressBar = this.add.graphics();
    const progressBox = this.add.graphics();
    progressBox.fillStyle(0x222222, 0.8);
    progressBox.fillRect(240, 270, 320, 50);

    this.load.on('progress', (value) => {
        progressBar.clear();
        progressBar.fillStyle(0xffffff, 1);
        progressBar.fillRect(250, 280, 300 * value, 30);
    });

    this.load.on('complete', () => {
        progressBar.destroy();
        progressBox.destroy();
    });

    // Queue your assets
    this.load.image('sky', 'assets/sky.png');
    // ... more assets
}

所有文件类型参考

所有 this.load 方法都接受位置参数或单个配置对象。它们也接受配置对象数组,用于批量加载同类型的多个文件。完整的参数表请参见 references/REFERENCE.md。

纹理: image、spritesheet、atlas、atlasXML、multiatlas、unityAtlas、aseprite、svg、htmlTexture、texture(压缩) 音频/视频: audio、audioSprite、video 数据: json、xml、text、binary、html、css、glsl 字体: bitmapFont、font 瓦片地图: tilemapTiledJSON、tilemapCSV、tilemapImpact 其他: animation、pack、script、scripts、plugin、scenePlugin、sceneFile

事件

所有事件都在加载器实例(this.load)上发出。

事件字符串回调签名描述
'addfile'(key, type, loader, file)一个文件被添加到加载队列
'start'(loader)加载器已启动。进度为零
'load'(file)单个文件加载完成(在处理/缓存之前)
'fileprogress'(file, percentComplete)单个文件的下载进度(0-1)。仅在浏览器提供 lengthComputable 时触发
'progress'(value)整体加载进度更新(0-1)
'postprocess'(loader)所有文件已加载并处理完成,在内部清理之前
'filecomplete'(key, type, data)任意文件加载并处理完成
'filecomplete-{type}-{key}'(key, type, data)特定文件完成(例如 'filecomplete-image-hero')
'loaderror'(file)一个文件加载失败
'complete'(loader, totalComplete, totalFailed)队列中的所有文件都已完成
事件生命周期顺序
  1. 'start' - Loader 开始
  2. 'fileprogress' - 单个文件进度(如可用,每个文件重复触发)
  3. 'load' - 每个文件下载完成
  4. 'filecomplete-{type}-{key}' - 特定文件处理并缓存完成
  5. 'filecomplete' - 通用的单文件完成
  6. 'progress' - 整体进度更新
  7. 'postprocess' - 所有文件完成,清理之前
  8. 'complete' - 一切完成

注意事项与常见错误

键在其类型内必须唯一。 加载第二张与现有图片键相同的图片会记录警告并跳过。如果需要替换,请先从 Texture Manager 中移除旧纹理。

Sprite sheet 与 atlas 不同。 对于固定尺寸的帧网格(按索引引用),使用 spritesheet()。对于带有命名帧的打包纹理图集,使用 atlas()。

在 preload 之外忘记调用 this.load.start()。 如果在 create() 或之后调用加载方法,Loader 不会自动启动。必须手动调用 this.load.start()。

路径必须以 / 结尾。 如果调用 this.load.setPath(),它会自动追加斜杠。如果直接设置 this.load.path,必须自己包含末尾斜杠。

音频格式回退。 始终提供多种音频格式(至少 OGG + MP3)以支持跨浏览器。Loader 会选择浏览器支持的第一个格式。

Pack 文件可以覆盖 baseURL/path/prefix。 Pack 文件中的每个部分都可以设置自己的 baseURL、path 和 prefix 值。这些仅适用于该部分内的文件,并在该部分处理完成后恢复。

文件键包含前缀。 如果设置 this.load.setPrefix('MENU.') 并加载键为 'bg' 的图片,实际缓存键变为 'MENU.bg'。引用该资源时必须使用完整键。

maxRetries 属性(默认值:2) 控制 Loader 在放弃之前重试失败文件的次数。这在创建时根据 this.load.maxRetries 按文件设置。在文件添加后调整它对这些文件没有影响。

图片加载类型。 默认情况下,图片通过 XHR(作为 blob)加载。在 loader 配置中设置 imageLoadType: 'HTMLImageElement' 以改用 <img> 标签加载,这在某些环境中可以帮助解决 CORS 问题。

本地文件方案。 Loader 默认将 file:// 和 capacitor:// 识别为本地方案(通过 localSchemes)。从本地方案加载的文件会跳过 CORS 头。

跨源。 从不同域加载资源时,在 loader 配置中设置 crossOrigin: 'anonymous'(或通过 this.load.setCORS('anonymous')),尤其是在这些纹理会与 WebGL 一起使用时。

键区分大小写并按类型作用域。 'Player' 和 'player' 是不同的键。图片键 'player' 和音频键 'player' 可以共存而不冲突。

重复键会被静默忽略。 如果 'bg' 已存在于纹理缓存中,第二次调用 this.load.image('bg', ...) 不会做任何事。要替换,请先移除旧资源。

场景的 update() 在 preload 期间不会触发。 在资源加载期间,update() 会暂停。但是,preupdate、postupdate 和 render 仍会触发。

进度可能下降。 如果在加载中途添加新文件(例如,通过 filecomplete 链式调用),进度值可能会下降,因为总文件数增加了。

场景 Payload(在 Preload 之前加载)

通过在 Scene 构造函数中定义 pack,可以在 preload() 运行之前加载文件。这对于加载进度条资源很有用。

class BootScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'BootScene',
            pack: {
                files: [
                    { type: 'image', key: 'bar', url: 'loaderBar.png' }
                ]
            }
        });
    }
    // 'bar' is already available in preload()
}
在加载中途添加文件

使用单文件完成事件在活动加载会话期间链式加载依赖项。

preload() {
    this.load.json('level1', 'level1.json');
    this.load.on('filecomplete-json-level1', (key, type, data) => {
        this.load.image(data.images);
        this.load.spritesheet(data.spritesheets);
    });
}
内联 Pack 清单

Pack 数据可以内联提供,而不是从 URL 提供。

preload() {
    this.load.pack('manifest', {
        section1: {
            prefix: '',
            path: 'assets/',
            defaultType: 'image',
            files: [
                { type: 'image', key: 'bg', url: 'bg.png' },
                { type: 'spritesheet', key: 'player', url: 'player.png', frameConfig: { frameWidth: 32, frameHeight: 32 } }
            ]
        }
    });
}
缓存系统

已加载的资源会进入所有 Scene 共享的全局缓存。纹理会存储在 Texture Manager(this.textures)中;其他资源类型会进入 this.cache 下的类型化子缓存。

// Access cached data
const json = this.cache.json.get('levelData');
const text = this.cache.text.get('dialogue');

// Check existence
this.cache.json.exists('levelData'); // or .has('levelData')
this.textures.exists('hero');

// Remove assets to free memory
this.textures.remove('hero');
this.cache.audio.remove('bgm');

// Listen for cross-scene texture additions
this.textures.on('addtexture-mapKey', (texture) => {
    // Another scene loaded 'mapKey' — now available here
});

缓存子类型:this.cache.text、this.cache.json、this.cache.audio、this.cache.binary、this.cache.shader、this.cache.xml。完整 Cache API 请参见 references/REFERENCE.md。

源文件映射

完整的源文件映射和 Cache API 参考请参见 references/REFERENCE.md。

关键文件:src/loader/LoaderPlugin.js(主 Loader)、src/loader/File.js(基础 File 类)、src/loader/filetypes/(所有文件类型加载器)、src/loader/events/(事件常量)。

评论

支持 Markdown