Skip to content
资源加载与资源下载

资源加载与资源下载

阅读本文预计10分钟

在游戏中资源在使用前都需要进行下载和加载过程。学习资源下载和加载的相关知识可以辅助用户优化资源加载的顺序和时机,提升游戏性能。

概述

资源下载指的是通过网络从云端资源库将资源下载到本地进行使用。而资源加载是将本地资源加载到游戏的缓存中,方便游戏运行后能随时使用。资源下载和资源加载都需要时间,如何处理好这段时间是游戏开发者需要关注的重点。编辑器中关于资源下载用户不用太过关注,而资源加载对内存,游戏拉起时间以及CPU性能的影响都需要开发者去选择合适的方式去兼顾。

资源下载

在编辑器的【资源库】中,提供了很多给用户使用的模型、材质、贴图、特效、动作、声音等相关资源。要想在项目开发过程中使用这些资源,你首先需要将它们下载到本地。从资源库拖出资源放置到【场景】中或者【对象管理器】下会自动执行下载流程,场景中对象会在下载完成后显示出来。

img

资源加载

资源加载指的是游戏运行过程中将已经使用或者即将使用到的资源加载进缓存的行为,这样每次使用资源时就不会陷入需要等待资源加载的情况。下方示例展示了将项目中【默认UI】的 "Jump" 按钮图片更改为一个未优先加载的UI贴图资源造成切换延迟的情况。在【工程内容】视图中的【脚本】栏中找到 "UIDefault" 脚本,将将下列代码补充到脚本中的onStart方法:在按下 "Jump" 按钮时会将按钮贴图切换为 "37718";

TypeScript
JumpBtn.onPressed.add(()=>{
    JumpBtn.pressedImageGuid = "37718";
    JumpBtn.disableImageGuid = "37718";
    JumpBtn.normalImageGuid = "37718";
});
JumpBtn.onPressed.add(()=>{
    JumpBtn.pressedImageGuid = "37718";
    JumpBtn.disableImageGuid = "37718";
    JumpBtn.normalImageGuid = "37718";
});

img

为了使资源不要等到使用的时候再加载,编辑器下提供了一种方式帮助用户去提前加载会使用到的资源:将使用到的资源拖入【对象管理器】下的【优先加载】栏。【对象管理器】中的对象使用的资源在游戏运行后都会默认进行加载,与拖入【优先加载】栏的效果一样。需要注意的是,预加载的资源越多,进入游戏的时间越慢。在编辑状态测试游戏时主要是资源加载进缓存的时间,而发布的线上游戏还需要增加资源下载的时间。

优先加载栏

【优先加载】栏中的资源在游戏运行后都会默认进行加载,将资源拖入后资源即被标记为"需要预加载"。【对象管理器】中已经被对象使用的资源无需再次拖入优先加载栏。资源拖入完成后保存工程

img

代码中动态下载与加载

由于预加载资源越多进入游戏的时间就越长,因此为了解决这个问题并且为了满足动态的加载和表现不同的资源而产生的需求,编辑器还提供两种动态进行资源加载的方式去辅助开发者以更灵活更主动的方式去进行资源的下载/加载操作。

使用资源下载/加载接口

编辑器提供了资源下载/加载接口,以便用户自己决定在游戏过程中适当的时机去执行资源下载/加载操作。用户只需要传入资源ID即可。assetLoaded接口可以检查某个资源是否加载,而asyncDownloadAsset可以动态下载并加载对应的资源。使用示例如下:

TypeScript
/**
 * @groups UTILITY
 * @description 资源是否加载
 * @effect 调用端生效
 * @param InAssetId usage:资源ID
 * @returns 未加载将返回false
 */
function assetLoaded(InAssetId: string): boolean;

/**
 * @description 资源下载
 * @groups UTILITY
 * @effect 调用端生效
 * @param InAssetId usage:资源ID
 * @returns 下载失败将返回false
 */
function asyncDownloadAsset(InAssetId: string): Promise<boolean>;
/**
 * @groups UTILITY
 * @description 资源是否加载
 * @effect 调用端生效
 * @param InAssetId usage:资源ID
 * @returns 未加载将返回false
 */
function assetLoaded(InAssetId: string): boolean;

/**
 * @description 资源下载
 * @groups UTILITY
 * @effect 调用端生效
 * @param InAssetId usage:资源ID
 * @returns 下载失败将返回false
 */
function asyncDownloadAsset(InAssetId: string): Promise<boolean>;
TypeScript
protected async onStart(): Promise<void> {
    AssetUtil.asyncDownloadAsset("37718").then((result: boolean) => {
        console.log("Resoure 37718 " + result);
    });

    // 作用同上
    // let result = await AssetUtil.asyncDownloadAsset("37718");
    // console.log("Resoure 37718 " + result);
    
    console.log("Resoure 37718 " + AssetUtil.assetLoaded("37718"));
}
protected async onStart(): Promise<void> {
    AssetUtil.asyncDownloadAsset("37718").then((result: boolean) => {
        console.log("Resoure 37718 " + result);
    });

    // 作用同上
    // let result = await AssetUtil.asyncDownloadAsset("37718");
    // console.log("Resoure 37718 " + result);
    
    console.log("Resoure 37718 " + AssetUtil.assetLoaded("37718"));
}

资源下载过程是异步的,但是资源加载过程不是异步的。所以动态加载资源会挤占游戏主线程,对CPU性能影响比较大,请谨慎选择游戏场景使用。

通过异步接口使用资源

如果资源因加载导致的表现延迟对游戏体验影响较大或者影响代码逻辑,那么可以使用异步接口去保障生成对象后对应的资源是加载完成的。通常用于异步生成某些资源对象例如特效,音效或者模型。异步接口可以保证获取到对应的对象时资源下载加载完成,而不会因为资源延迟原因导致代码操作出现异常。

TypeScript
let newSound = await GameObject.asyncSpawn("127210") as Sound;
let newSound = await GameObject.asyncSpawn("127210") as Sound;

动态加载与静态加载的优缺点

静态加载动态加载
优点可以在场景加载过程中完成自身的加载过程,所以在场景运行期间该资源没有任何性能隐患;另外在使用资源时无需担心延迟问题。根据游戏设计要求,有些资源在场景开始时无法确定哪些会使用,必须动态加载;动态资源可以在场景运行的任何时间加载,开发者具有很强的灵活性和主动性。
缺点只支持不变的静态资源,无法根据游戏的实际需要灵活更换不同资源;此外场景进入加载时间会显著增加。动态资源加载需要开发者更高的技巧;而一旦缺乏对其合理的控制,游戏的性能问题将无法避免。