Skip to content

Cocos Creator 资源动态加载

在游戏开发中,并非所有资源都需要在启动时加载完毕。将资源放在 resources 目录下,按需动态加载,可以有效缩短初始加载时间、降低内存占用。

基本规则

  • 需要动态加载的资源必须放在 resources/ 目录下(或其子目录)
  • 加载完成后要及时释放不再使用的资源,防止内存泄漏
  • 2.x 使用引用计数(release);3.x 使用 decRef()releaseAsset()

2.x

加载单个资源

ts
// 加载图片
cc.loader.loadRes("images/hero", cc.SpriteFrame, (err, spriteFrame) => {
    if (err) {
        cc.error("加载失败:", err);
        return;
    }
    this.heroSprite.spriteFrame = spriteFrame;
});

// 加载预制体
cc.loader.loadRes("prefabs/Enemy", cc.Prefab, (err, prefab) => {
    if (err) return;
    const enemy = cc.instantiate(prefab);
    this.node.addChild(enemy);
});

加载整个目录

ts
cc.loader.loadResDir("maps", cc.JsonAsset, (err, assets) => {
    if (err) return;
    assets.forEach(asset => {
        cc.log("加载到地图:", asset.name, asset.json);
    });
});

释放资源(避免内存泄漏)

ts
// 释放单个资源
cc.loader.releaseRes("images/hero", cc.SpriteFrame);

// 释放整个目录下的资源
cc.loader.releaseResDir("maps");

3.x

加载单个资源

ts
// 加载图片
resources.load("images/hero", SpriteFrame, (err, spriteFrame) => {
    if (err) {
        console.error("加载失败:", err);
        return;
    }
    this.heroSprite.spriteFrame = spriteFrame;
});

// 加载预制体(async/await 写法)
async loadEnemy() {
    return new Promise<Prefab>((resolve, reject) => {
        resources.load("prefabs/Enemy", Prefab, (err, prefab) => {
            if (err) { reject(err); return; }
            resolve(prefab);
        });
    });
}

加载整个目录

ts
resources.loadDir("maps", JsonAsset, (err, assets) => {
    if (err) return;
    assets.forEach(asset => {
        console.log("加载到地图:", asset.name, asset.json);
    });
});

释放资源(引用计数)

3.x 使用引用计数管理资源生命周期:

ts
// 方式一:减少引用计数(引用为0时自动释放)
spriteFrame.decRef();

// 方式二:强制释放(不推荐,可能引发其他地方报错)
assetManager.releaseAsset(spriteFrame);

注意decRef() 只在资源引用计数降为 0 时才真正释放,通常配合 addRef() 手动管理:

ts
// 加载时增加引用
asset.addRef();
// 使用完毕后减少引用
asset.decRef();

常见问题

问题原因解决方案
资源加载不到文件不在 resources/ 目录下将资源移入 resources/ 子目录
内存持续增长加载后未释放切换场景时调用 release/decRef
释放后报错资源被多处引用2.x 改用引用计数;3.x 使用 addRef/decRef