参赛说明

这是这个月在Gad上写完的资源加载与释放的一个解决方案,经过朋友提醒刚好可以拿来参加比赛,于是转载过来。

u3d的性能会有几个层级的考虑:

1、设计层,资源面数,使用技术消耗,法线多少,shader如何,是否程序材质,动态减面。

2、资源层,资源是否预加载,动态加载,动态释放,是否缓存,是否泄漏。

3、代码层,是否使用了过多的低效代码。

而本篇,则是在资源预加载与动态释放下手,尝试着用一种自动化的方案,去优化大型项目中的资源加载与释放过程。

需求环境

在上一级的【解决方案】文章中,我们设计出了动态加载资源的业务流程,而这一节,我们就通过一些简单的代码,来实现出业务流程中的效果。

吸取之前文章的经验,如果按照正式项目的规格开发,本篇文章就会非常冗余,所以我们优化一下,仅仅针对技术点进行讲解与释放,具体与工程相关的,我们就不再文章中讲解,但你可以在Github的工程中找到它们。、

现在,我们先回顾一下之前所设计出的业务流程。

102645qmtjzn5j5kvotzbz.png
那么,在这个业务流程中,我可以定义出在游戏运行时,资源有三种状态:

1、未加载

2、已经加载

3、已可以释放

三种状态了某个资源此时的最佳使用环境,也就是说,接下来需要使用的资源,我就放到池中,而接下来很长一段时间内不需要使用的资源,我就彻底释放掉。以确保程序的内存总是在可控范围之内。

设计

为了达到这样的目的,我们就需要划分三个模块去做。

1、最基础的资源加载,与池。

2、资源加载的自动记录过程。

3、资源加载的动态释放与加载过程。



首先,池,因为我们是模拟,所以这个就比较容易实现,在现实工程中,则可能需要考虑不同资源类型的具体逻辑。
 

  1. ///
  2.  
  3.  
  4. /// 池
  5. ///
  6.  
  7. Dictionary<int, stack<object=>> PoolDict = new Dictionary<int, stack<object=>>();
  8.  
  9. ///
  10.  
  11. /// 正在工作的资源对象
  12. ///
  13.  
  14. Dictionary<object, int=> WorkingPool = new Dictionary<object, int=>();object,>object,>int,>int,>


PS: 在文章代码中并没有对预制体进行管理,这其实是不好的,最好手动的控制他们的加载与释放。

资源生命周期的自动记录

要记录资源的生命周期,首先我们得确定自己的游戏形势,如果是大世界类型的游戏,我们需要根据区域范围来确定资源表,那么如果是副本类型的,我们就需要以副本为单位记录一份资源表。

并且,有的资源我们希望是动态加载的,而有的资源,比如主角的特效,模型,音频等等,我们更希望它们是常驻的。所以,我们还需要区分一份资源是否需要动态加载。



知道了需求后,我们就可以对自动记录表进行设计。为了讲解清晰,我尽量的保持任何一个元素都只是为了测试,不与业务逻辑挂钩。

在工程中,你可以到之前我们创建过的DJAssetsDefine 命名空间,里面我们新添加了这一次需要使用到的记录表。

 

 

  1. [System.Serializable]
    • public class AssetPreConfig
      • {
        • ///
          •  
          •  
          • /// 资源ID
            • ///
              •  
              • public int AssetId;
                •  
                • ///
                  •  
                  • /// 加载时间
                    • ///
                      •  
                      • public float LordTime;
                        •  
                        •  
                        • ///
                          •  
                          • /// 下一个次同类资源的加载时间,-1 就是再也没有加载过了
                            • ///
                              •  
                              • public float NextTime = -1;
                                • }

代码如下:

 

 

  1. ///
    •  
    •  
    • /// 得到一个克隆体
      • ///
        •  
        • ///资源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);
                                          • }
第一次
102646a5qp2p2hxv64yhql.png此时记录表内的内容
第二次

103819i8vskdvcdvnp3g3n.png
可以看到,前两次的资源都有预加载,所以时间上间断了。而第三次资源,却比第一次还要多,因为中间发生了资源删除事件。

第三次

103840at2jr83qwqa8arja.png
这一次,没有任何资源是在使用时才被加载的,前2份资源也不会“轻易”的放弃了自己生命,而是等待这第3份的调用。

彻底完成了优化的过程。

结束语

如果和业务逻辑相结合,我们所演示的功能是不够的,但却构建了整个自动化的资源加载与释放的核心框架,使得我们在项目后续的开发过程中,尽可能的不会在IO方面遇到困难。

同时,如果我们能继续对这部分的工作进行优化,还能制作出更平缓的游戏资源IO流程。


锐亚教育

锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛