# 资源系统

纹理、材质、模型等游戏资源,在游戏项目中,它们是一系列静态文件;在游戏运行时,它们被实例化为一系列资源实例,被 UISprite、MeshRender 等 Component 依赖,参与渲染。
资源系统做了两件事:

  1. 在游戏项目构建时,打包资源文件。
  2. 在游戏运行时,加载资源文件,并创建资源实例。

先来了解资源是如何加载的。Loader 是用来加载资源的加载器 Class。资源系统的核心 API、也是 Loader 的核心 API,只有 2 个:

  • Loader.prototype.load() 用来异步加载资源。
  • Loader.prototype.getAsset() 用来同步获取资源。

engine.loader 是 Loader 在 engine 上的单例对象,你需要在在 engine.loader 上调用 .load() 和 .getAsset()。

Loader.prototype.load() 会返回一个 LoadTask,可以监听加载任务的结果,也可以中断它。

// 假设 SpriteFrame 的资源 id 是 1c8d38F-df4ac6I-01e81fL-345ee9E
const task = engine.loader.load("1c8d38F-df4ac6I-01e81fL-345ee9E");
task.promise.then((spriteFrame) => {
  console.log(spriteFrame)
}).catch((error) => {
  console.error(error);
})
// 中断任务,task.promise 的 catch 会执行
task.abort();

httpRetryCount 可以指定下载资源文件重试次数,priority 可以指定下载资源文件的优先级。
在 Loader 内部对并发的下载数量有限制,priority 更高的资源加载涉及到的文件下载会被优先发起下载。

engine.loader.load("1c8d38F-df4ac6I-01e81fL-345ee9E", {
  httpRetryCount: 2,
  priority: 10
}).promise.then((spriteFrame) => {
  console.log(spriteFrame)
})

资源加载成功后,如果想要以同步调用的方式获取资源实例,可以调用 Loader.prototype.getAsset()。

// 如果尚未加载、加载未完成,会抛出错误
try {
  const spriteFrame = engine.loader.getAsset("1c8d38F-df4ac6I-01e81fL-345ee9E");
}
catch (e) {
  console.error(e)
}

资源系统有 16 种资源:

类型 说明
Scene 场景
Prefab 预制
Texture2D 2d 纹理
TextureCube 立方体纹理
RenderTexture 可渲染纹理
SpriteFrame 精灵帧
Mesh 网格
Material 材质
Effect 特效
Font 字体
BitmapFont 位图字体
AnimationClip 动画片段
AnimatorController 动画状态机
Avatar 骨骼
Variant shader 代码。包含 vertex 代码和 fragment 代码,在渲染用到该 shader 时,shader 代码会被编译成 shader 对象并参与渲染。
Raw 纯文件。不被资源系统理解,而是游戏自定义的资源。比如游戏关卡的配置表等。
Script .js 文件。加载时会通过 require() 方法被执行。

资源是一个抽象概念,一个资源可能涉及一个或者多个文件。在运行时,资源系统根据这一个或者多个文件的内容,创建资源实例。

以 Texture2D 为例,一个 Texture2D 涉及两个文件:

  • 包含 pixelFormat、wrapU、wrapV 等 Texture2D 配置信息的描述文件 .texture2d,格式为 JSON。
  • 图片文件,可能是 .png,或者是压缩纹理 .astc .etc2。

.texture2d 文件依赖图片文件。在 .texture2d 的配置信息中,file.src 字段记录了对图片文件的引用,这个引用是一个唯一的 id。在资源系统中,每个文件和资源都有一个 id。

文件之间存在依赖关系,资源之间也存在依赖关系。比如一张 2048x2048 的图片上可以切出多个 SpriteFrame,那么这多个 SpriteFrame 就都依赖一个 2048x2048 的 Texture2D。

SpriteFrame 有着如下的依赖链路:SpriteFrame -> Texture2D -> Texture2D 描述文件 -> 图片文件,在加载 SpriteFrame 时会依照同样的顺序加载依赖。

开发者不需要在代码中处理依赖关系,更无须处理资源文件的读取,只需调用 Loader.prototype.load(),就可以获取加载并实例化后的资源。