版本: v3.4.0

参考: resources资源加载


简介

项目中所有需要通过脚本动态加载的资源可以使用resources.load接口进行加载,且资源相关一定要放在assets\resources的目录或子目录下。

assets\resources目录下的资源要注意: 如果只是依赖于外部的资源,而不需要被resources.load接口调用,就不要放在该目录下。

这样会导致问题:

  • 增大config.json的大小
  • 项目中无用的资源,无法在构建的过程中自动剔除
  • 构建过程中,JSON的自动合并策略将受到影响,无法尽可能的合并零碎的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");
});
  • 加载图片的SpriteFrameTexture2DSpriteAtlas图集资源
/*
* 图片相关,在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;
});
  • 加载模型的MeshMeterialSkeleton资源
// 加载模型中的网格资源
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常用接口

关于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的主要接口如下:

接口当中所提到的onProgressonComplete是回调接口, 他们对应的主要参数:

/*
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");

简单的写下这个,就当是对代码有个简单的理解吧。


08-06 04:14