版本: v3.4.0
参考: resources资源加载
项目中所有需要通过脚本动态加载的资源可以使用resources.load
接口进行加载,且资源相关一定要放在assets\resources
的目录或子目录下。
在assets\resources
目录下的资源要注意: 如果只是依赖于外部的资源,而不需要被resources.load
接口调用,就不要放在该目录下。
这样会导致问题:
config.json
的大小关于resource.load
动态加载资源,它支持多种类型的添加:
Prefab
预制体资源// 加载prefab某个UI页面
resources.load("prefab/shopLayer", Prefab, (err, prefab) => {
if(err) {
console.log("resource load failed:" + err.message);
return;
}
const node = instantiate(prefab);
node.parent = this.node;
});
AnimationClip
动画资源// 加载 AnimationClip
resources.load("test assets/anim", AnimationClip, (err, clip) => {
this.node.getComponent(Animation).addClip(clip, "anim");
});
SpriteFrame
或Texture2D
或SpriteAtlas
图集资源/*
* 图片相关,在creator中它的格式为ImageAsset,它一般会生成格式:SpriteFrame和Texture
* 动态加载要在路径的后方去增加SpriteFrame或Texture的格式,否则将默认为ImageAsset格式
*/
// 通过加载SpriteFrame改变图片
const path = "textures/gold/spriteFrame";
resources.load(path, SpriteFrame, (err, spriteFrame) => {
const sprite = this.node.getComponent(Sprite);
sprite.spriteFrame = spriteFrame;
});
// 通过加载Texture2D来改变图片
const path = "textures/gold/texture";
resources.load(path, Texture2D, (err: any, texture: Texture2D) => {
const spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
const sprite = this.node.getComponent(Sprite);
sprite.spriteFrame = spriteFrame;
});
// 通过图集来改变改变图片
const path = "textures/fruit"
resources.load(path, SpriteAtlas, (err, atlas) => {
// 获取精灵帧
const frame = atlas.getSpriteFrame('fruit_0');
sprite.spriteFrame = frame;
});
Mesh
或Meterial
或Skeleton
资源// 加载模型中的网格资源
resources.load("Monster/monster", Mesh, (err, mesh) => {
this.node.getComponent(MeshRenderer).mesh = mesh;
});
// 加载模型中的材质资源
resources.load("Monster/monster-effect", Material, (err, material) => {
this.node.getComponent(MeshRenderer).material = material;
});
// 加载模型中的骨骼
resources.load("Monster/Armature", Skeleton, (err, skeleton) => {
this.node.getComponent(SkinnedMeshRenderer).skeleton = skeleton;
});
关于reources
的接口实现,通过cc.d.ts可以看到:
// resources 是一个 bundle,用于管理所有在 assets/resources 下的资源
export const resources: AssetManager.Bundle;
Bundle可以简单理解为资源模块化,将贴图,脚本,场景等资源划分为一个Bundle。
有助于在游戏运行的过程中,通过加载不同的Bundle 减少启动是需要加载的资源数量。
更多参考:Asset Bundle
关于AssetManager
需要注意:
// 通过cc.assetManager调用
export const assetManager: AssetManager;
export class AssetManager {};
// 使用的命名空间
export namespace AssetManager {
// 管线能执行任务达到某个效果
export class Pipeline {}
// 任务用于在管线中运行以达成某种效果
export class Task {}
// 请求的相关信息集合
export class RequestItem {}
// 一个包含一定数量资源(包括场景)的包,你可以加载,预加载,释放此包内的资源
export class Bundle {}
// 内置 bundle
export enum BuiltinBundleName {
RESOURCES = "resources",
MAIN = "main",
START_SCENE = "start-scene"
}
}
对于Bundle
的主要接口如下:
名字 | 描述 |
---|---|
name |
bundle的名称 |
base |
bundle的根路径 |
getInfoWithPath(path, type) |
通过路径获取指定资源的配置信息 |
getDirWithPath(path, type, out) |
获取某个指定文件夹下的所有资源信息 |
getAssetInfo(uuid) |
通过uuid获取资源信息 |
getSceneInfo(name) |
通过场景名获取场景信息 |
load(path, type, onPrgress, onComplete) |
通过相对路径加载资源 |
loadDir(dir, type, onProgree, onComplete) |
加载目标文件夹中的所有资源 |
loadScene(name, optins, onProgress, onComplete) |
通过场景名称加载分包中的场景 |
preload(paths,type, onProgress, onComplete) |
通过相对路径预加载分包中的资源 |
preloadDir(dir, type, onProgress, onComplete) |
预加载目标文件夹中的所有资源 |
preloadScene(name, optins, onProgress, onComplete) |
通过场景名称预加载分包中的场景 |
releaseUnusedAssets() |
释放此包中的所有没有用到的资源 |
releaseAll() |
释放此包中的所有资源 |
接口当中所提到的onProgress
和onComplete
是回调接口, 他们对应的主要参数:
/*
onProgress 加载进度改变时的回调
finished: 已完成的加载数目
total: 需要加载的总数目
item: 请求项相关
*/
onProgress: __private.cocos_core_asset_manager_shared_ProgressCallback | null
export type cocos_core_asset_manager_shared_ProgressCallback = (finished: number, total: number, item: AssetManager.RequestItem) => void;
/*
onComplete 加载完成回调
err: 错误信息相关,包含name, message, stack等
data: 对应的item数据
*/
onComplete: __private.cocos_core_asset_manager_shared_CompleteCallbackWithData<T>
export type cocos_core_asset_manager_shared_CompleteCallbackWithData<T = any> = (err: Error | null, data: T) => void;
interface Error {
name: string;
message: string;
stack?: string;
}
对于load、preload、loadDir、preloadDir、loadScene、preloadScene 等,均提供了多种不同的函数重载的实现, 就不在重复赘述了。
在项目当中,使用resources.load
动态加载资源,某些时候会出现卡顿。
我们可以调用preload、preloadDir等,对内置Bundle下的resources资源进行预加载,它的特点是:
需要注意的是:预加载资源,并不影响我们使用正常加载接口。
简单的实例:
// 预加载resources目录下某个子目录
resource.preloadDir("prefab", Prefab, (err, data) => {});
// 预加载某个资源
resources.preload("music/background", AudioClip, (err, data) => {});
// 预加载某个SpriteFrame
const url = 'textures/bg_1/spriteFrame'
resources.preload(url, SpriteFrame);
resources.load(url, SpriteFrame, (err, spriteFrame) => {
this.node.getComponent(Sprite).spriteFrame = spriteFrame;
});
以Loading页面的加载进度为例,假设我们想加载所有的resources资源,可以:
import { _decorator, assetManager, clamp01, Component, director, Label, ProgressBar, resources } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('UI_LoadingLayer')
export class UI_LoadingLayer extends Component {
// 进度条
@property(ProgressBar)
loadBar: ProgressBar = null;
// 描述文本
@property(Label)
desc: Label = null;
protected onLoad(): void {
// 通过cc.assetManager获取内置的resources包
cosnt bundle = assetManager.resources;
// 获取resources下的所有资源信息
const resourcePaths = bundle.getDirWithPath("./");
// 获取文件最大个数
const maxLen = resourcePaths.length;
// 设置进度相关
this.desc.string = ""
this.loadBar.progress = 0;
// 通过资源信息表获取路径,使用preload进行预加载
let loadCount = 0;
for(let i = 0; i < maxLen; ++i) {
const uuid = resourcePaths[i].uuid;
const path = resourcePaths[i].path;
resources.preload(path, (err: Error | null, data: any) => {
if (err) {
console.log("preload failed: " + err.message);
return;
}
loadCount++;
// 通过文本显示加载的文件
this.desc.string = `加载${path}`
// 进度条改变
this.loadBar.progress = clamp01(loadCount/maxLen);
})
}
}
}
关于resources Bundle的获取,主要通过cc.assetManager
来获取
// 通过变量
let resourceBundle = assetManager.resources;
let mainBundle = assetManager.main;
// 使用getBundle来获取
let resourceBundle = assetManager.getBundle("resources");
// 通过集合来获取
let bundle = assetManager.bundles.get("resources");
简单的写下这个,就当是对代码有个简单的理解吧。