1. 本地资源加载(随包体)
(1) Resources 系统(少量高频资源)
适用于小量、频繁使用的资源(如UI图标、音效)。
// 单个加载
resources.load("images/button", SpriteFrame, (err, spriteFrame) => {
this.button.spriteFrame = spriteFrame;
});
// 批量加载目录
resources.loadDir("images/ui", (err, assets) => {
// assets 是该目录下所有资源数组
});
(2) Asset Bundle(模块化资源包)
这是Cocos Creator的核心资源管理方式,支持分包、热更新。
// 配置bundle(在构建时指定)
// 创建 bundles/main, bundles/level1 等bundle
// 使用bundle
// 1. 加载bundle
assetManager.loadBundle('main', (err, bundle) => {
if (err) { console.error(err); return; }
// 2. 从bundle中加载资源
bundle.load('ui/panel', Prefab, (err, prefab) => {
if (err) { console.error(err); return; }
const node = instantiate(prefab);
this.node.addChild(node);
});
});
2. 远程资源加载(动态下载)
(1) 远程Asset Bundle
这是小游戏最佳实践,可以极大减小首包体积。
async loadRemoteBundle() {
// 远程bundle地址
const bundleUrl = "https://cdn.yourgame.com/bundles/level1";
try {
// 加载远程bundle
const bundle = await new Promise((resolve, reject) => {
assetManager.loadBundle(bundleUrl, (err, bundle) => {
err ? reject(err) : resolve(bundle);
});
});
// 从bundle加载资源
const prefab = await new Promise((resolve, reject) => {
bundle.load('monster/slime', Prefab, (err, prefab) => {
err ? reject(err) : resolve(prefab);
});
});
// 实例化
const monster = instantiate(prefab);
this.node.addChild(monster);
} catch (error) {
console.error("加载失败:", error);
}
}
(2) 远程单文件资源
适合配置文件、少量图片等。
// 加载远程图片
loadRemoteImage(url) {
return new Promise((resolve, reject) => {
assetManager.loadRemote(url, (err, texture) => {
if (err) {
reject(err);
return;
}
const spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
resolve(spriteFrame);
});
});
}
// 加载JSON配置
async loadConfig() {
const configUrl = "https://cdn.yourgame.com/config/game.json";
try {
const json = await new Promise((resolve, reject) => {
assetManager.loadRemote(configUrl, (err, data) => {
err ? reject(err) : resolve(data);
});
});
console.log("配置加载成功:", json);
return json;
} catch (error) {
console.error("配置加载失败:", error);
}
}
3. 小游戏平台特有方案
微信小游戏分包加载
// 1. 在game.json中配置分包
// 2. 代码中加载分包
wx.loadSubpackage({
name: 'level1', // 分包名
success: () => {
console.log('分包加载成功');
// 分包资源现在可用
},
fail: (err) => {
console.error('分包加载失败', err);
}
});
临时文件下载(微信小游戏)
// 下载文件到本地临时路径
wx.downloadFile({
url: 'https://example.com/image.png',
success: (res) => {
if (res.statusCode === 200) {
// 从临时路径加载
assetManager.loadRemote(res.tempFilePath, (err, texture) => {
if (!err) {
const spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
this.sprite.spriteFrame = spriteFrame;
}
});
}
}
});
实战资源架构示例
// 资源管理器的简化实现
class ResourceManager {
constructor() {
this.bundles = new Map(); // 存储已加载的bundle
}
// 1. 预加载必要资源(启动时)
async preloadEssential() {
// 加载主bundle
const mainBundle = await this.loadBundle('main');
// 加载必要的UI资源
const uiResources = await this.loadFromBundle(mainBundle, [
'ui/loading',
'ui/buttons',
'ui/fonts'
]);
return uiResources;
}
// 2. 按场景加载资源
async loadSceneResources(sceneName) {
// 动态决定加载本地还是远程bundle
const bundleName = `scene_${sceneName}`;
// 检查是否已下载
if (!this.isBundleDownloaded(bundleName)) {
// 下载远程bundle
const remoteUrl = this.getBundleUrl(bundleName);
await this.downloadBundle(remoteUrl, bundleName);
}
// 加载bundle
const bundle = await this.loadBundle(bundleName);
// 加载场景资源
const sceneAssets = await this.loadFromBundle(bundle, [
'textures',
'prefabs',
'animations'
]);
return sceneAssets;
}
// 3. 动态资源加载
async loadDynamicAsset(assetPath) {
// 先尝试从已加载bundle中查找
for (const bundle of this.bundles.values()) {
if (bundle.getInfoWithPath(assetPath)) {
return this.loadFromBundle(bundle, assetPath);
}
}
// 从网络动态下载单个资源
return this.loadRemoteAsset(this.getRemoteUrl(assetPath));
}
// 4. 资源清理
releaseUnusedResources() {
// 根据引用计数释放资源
for (const [bundleName, bundle] of this.bundles) {
if (!this.isBundleInUse(bundleName)) {
bundle.releaseAll();
this.bundles.delete(bundleName);
}
}
}
}
加载策略选择指南
| 资源类型 | 推荐加载方式 | 原因 |
|---|---|---|
| 核心UI、通用音效 | Resources 或 主Bundle | 启动时需要,使用频率高 |
| 游戏场景资源 | Asset Bundle(可远程) | 模块化,可动态下载,减小首包 |
| 大型图集/动画 | Asset Bundle | 方便批量加载和释放 |
| 配置文件 | 远程单文件 | 可热更新,无需重新发包 |
| 用户头像/分享图 | assetManager.loadRemote | 来自网络,动态变化 |
| 第三方SDK资源 | 小游戏分包 | 符合平台规范,隔离依赖 |
小游戏最佳实践
- 首包优化
- 首包控制在4MB内(微信小游戏标准)
- 只放启动必须资源
- 使用远程Bundle延迟加载
- 缓存策略
// 实现简单的资源缓存 class ResourceCache { constructor() { this.cache = new Map(); this.maxSize = 50; // 最大缓存数 } async get(url) { if (this.cache.has(url)) { return this.cache.get(url); } const resource = await this.loadResource(url); // LRU缓存策略 if (this.cache.size >= this.maxSize) { const firstKey = this.cache.keys().next().value; this.cache.delete(firstKey); } this.cache.set(url, resource); return resource; } } - 加载状态管理
- 显示加载进度条
- 实现重试机制
- 提供跳过选项(必要时)
- 内存管理
// 及时释放不用的资源 resources.release('scene1/textures'); bundle.releaseAll(); assetManager.releaseAsset(texture);
总结
小游戏资源加载是多层次、多策略的混合方案:
- 核心:Asset Bundle 系统(支持本地/远程)
- 补充:
resources(简单场景)、assetManager.loadRemote(单文件) - 平台:小游戏分包、临时文件系统
- 优化:缓存、预加载、懒加载、资源池
实际项目建议:
- 核心框架和首屏UI → 主Bundle
- 不同游戏场景 → 多个远程Bundle
- 用户生成内容 →
loadRemote动态下载 - 平台SDK → 小游戏分包
这样既控制了包体大小,又保证了游戏体验的流畅性。