参赛说明
这是这个月在Gad上写完的资源加载与释放的一个解决方案,经过朋友提醒刚好可以拿来参加比赛,于是转载过来。
u3d的性能会有几个层级的考虑:
1、设计层,资源面数,使用技术消耗,法线多少,shader如何,是否程序材质,动态减面。
2、资源层,资源是否预加载,动态加载,动态释放,是否缓存,是否泄漏。
3、代码层,是否使用了过多的低效代码。
而本篇,则是在资源预加载与动态释放下手,尝试着用一种自动化的方案,去优化大型项目中的资源加载与释放过程。
需求环境
在上一级的【解决方案】文章中,我们设计出了动态加载资源的业务流程,而这一节,我们就通过一些简单的代码,来实现出业务流程中的效果。
吸取之前文章的经验,如果按照正式项目的规格开发,本篇文章就会非常冗余,所以我们优化一下,仅仅针对技术点进行讲解与释放,具体与工程相关的,我们就不再文章中讲解,但你可以在Github的工程中找到它们。、
现在,我们先回顾一下之前所设计出的业务流程。
那么,在这个业务流程中,我可以定义出在游戏运行时,资源有三种状态:
1、未加载
2、已经加载
3、已可以释放
三种状态了某个资源此时的最佳使用环境,也就是说,接下来需要使用的资源,我就放到池中,而接下来很长一段时间内不需要使用的资源,我就彻底释放掉。以确保程序的内存总是在可控范围之内。
设计
为了达到这样的目的,我们就需要划分三个模块去做。
1、最基础的资源加载,与池。
2、资源加载的自动记录过程。
3、资源加载的动态释放与加载过程。
池
首先,池,因为我们是模拟,所以这个就比较容易实现,在现实工程中,则可能需要考虑不同资源类型的具体逻辑。
- ///
-
-
- /// 池
- ///
-
- Dictionary<int, stack<object=>> PoolDict = new Dictionary<int, stack<object=>>();
-
- ///
-
- /// 正在工作的资源对象
- ///
-
- Dictionary<object, int=> WorkingPool = new Dictionary<object, int=>();object,>object,>int,>int,>
PS: 在文章代码中并没有对预制体进行管理,这其实是不好的,最好手动的控制他们的加载与释放。
资源生命周期的自动记录
要记录资源的生命周期,首先我们得确定自己的游戏形势,如果是大世界类型的游戏,我们需要根据区域范围来确定资源表,那么如果是副本类型的,我们就需要以副本为单位记录一份资源表。
并且,有的资源我们希望是动态加载的,而有的资源,比如主角的特效,模型,音频等等,我们更希望它们是常驻的。所以,我们还需要区分一份资源是否需要动态加载。
表
知道了需求后,我们就可以对自动记录表进行设计。为了讲解清晰,我尽量的保持任何一个元素都只是为了测试,不与业务逻辑挂钩。
在工程中,你可以到之前我们创建过的DJAssetsDefine 命名空间,里面我们新添加了这一次需要使用到的记录表。
- [System.Serializable]
- public class AssetPreConfig
- {
- ///
-
-
- /// 资源ID
- ///
-
- public int AssetId;
-
- ///
-
- /// 加载时间
- ///
-
- public float LordTime;
-
-
- ///
-
- /// 下一个次同类资源的加载时间,-1 就是再也没有加载过了
- ///
-
- public float NextTime = -1;
- }
-
- ///
-
-
-
- ///
-
-
-
- ///
-
- ///
- {
- public class AssetPreConfig
代码如下:
- ///
-
-
- /// 得到一个克隆体
- ///
-
- ///资源id
- /// 是否预加载
- ///
- private Object getClone(int _id, bool _isPre = false)
- {
- //预加载直接返回新的
- if (_isPre) return Object.Instantiate(PoolDict[_id].pre); ;
-
- //池里有从池里拿
- if (PoolDict[_id].Pools.Count > 0)
- {
- currentIndex+= 1;
- return PoolDict[_id].Pools.Pop();
- }
-
- //记录下这次加载
- AutoLog(_id);
-
- //返回一个新的
- return Object.Instantiate(PoolDict[_id].pre);
- }
- return Object.Instantiate(PoolDict[_id].pre);
-
- AutoLog(_id);
-
- }
- return PoolDict[_id].Pools.Pop();
- currentIndex+= 1;
- {
- if (PoolDict[_id].Pools.Count > 0)
-
- if (_isPre) return Object.Instantiate(PoolDict[_id].pre); ;
- //预加载直接返回新的
- {
- private Object getClone(int _id, bool _isPre = false)
- ///
- /// 是否预加载
-
- ///
-
此时记录表内的内容
第二次
可以看到,前两次的资源都有预加载,所以时间上间断了。而第三次资源,却比第一次还要多,因为中间发生了资源删除事件。
第三次
这一次,没有任何资源是在使用时才被加载的,前2份资源也不会“轻易”的放弃了自己生命,而是等待这第3份的调用。
彻底完成了优化的过程。
结束语
如果和业务逻辑相结合,我们所演示的功能是不够的,但却构建了整个自动化的资源加载与释放的核心框架,使得我们在项目后续的开发过程中,尽可能的不会在IO方面遇到困难。
同时,如果我们能继续对这部分的工作进行优化,还能制作出更平缓的游戏资源IO流程。
锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛
- 还没有人评论,欢迎说说您的想法!