Cocos Creator 通用框架设计 —— 资源管理

Mark以下,慢慢看

可以pull一下最新的代码,新增了跳过当前场景资源的释放

再pull一下代码,可以看看 —— 获取场景对应的所有依赖资源的代码
其实就是 cc.director.getScene().dependAssets。

mark

mask

那么init和脚本的生命周期的执行顺序怎么确定的?比如 onload start等与init的执行顺序

mark

mask一下

hello,宝爷,你的这份资源管理和demo我研究了一波,有如下疑问:
虽说你做了资源引用计数管理,清理的时候能准确清除load过的资源,但是如果资源我只load一遍,但是其他地方使用几遍,然后再次删除,还是回到了问题原点,例如:我load一个spriteframe,然后在场景中的两个节点分别 sprite1.spriteframe = spriteframe;sprite2.spriteframe = spriteframe,使用完了之后,在移除sprite1时,我调用清除,把资源干掉了,会影响sprite2,这个咋处理额?因为sprite2使用现成的已加载过的资源,跳过了load引用计数标记额…

如果load同一张资源多次,分别使用,然后relase,会报错,原理如同1一样,不可能load同一张资源,还各种精确的makeUseKey, 然后release时也传入对应的makeUseKey吧?再说了一个项目中各种资源一般只会加载一次,肯定会重复多方向使用的,特别是合并图集drawcall等优化性能的时候,我不相信大多数人没遇到

求大佬解惑指点下思路?

这位同学说的很好,首先使用多次的问题,如你所说,就是各种makeUseKey,当出现各种makeUseKey的时候,我们马上就感到不方便了,我们希望更智能一点,不要让我知道makeUseKey这种事情的存在,通过封装一个中间层可以很大程度的缓解这个问题,当然,还取决于你想怎么使用资源,使用资源的方式我们希望能够遵循一定的规范,除非你很清楚在这个范围内这样子操作是没有问题的。

我们可能在任何地方去加载资源,但我们所希望释放资源的地方有两种:

  • 跟随某个对象的销毁而自动释放
  • 在某个地方手动释放

如果我使用一个组件,用于生成唯一的UseKey,并记录所有加载的资源,在组件销毁时释放所有记录的资源(这里对于还在加载中的资源需要特殊处理一下),那么每个有权力管理资源加载的节点,都可以使用这样的一个组件来管理,由于它们的UseKey都是不同的,整个资源的释放都会是安全的,不会互相干扰。

在场景中挂载这个组件,每个UI界面也挂载一个这样的组件,再提供一个便捷的方法,比如说包装一个方法,加载某资源,并指定其跟随某节点自动释放,如果说目标节点没有挂载该组件,就往其父节点找,找到最近的拥有该组件的节点,也可以选择当没有该组件时自动挂载该组件到目标节点。

这种拥有资源管理释放的关键节点,根据我的经验主要是以下3种:

  • 场景节点,但场景节点的资源释放还是有更多的优化空间(在做Cocos2d-x的时候我设计过一种自认为很不错的场景切换的资源加载卸载方案,通用的)
  • UI节点,伴随着界面关闭,到时候可以看我下一篇文章,最近太忙了,写文章的时间不多
  • 动态对象,比如说战斗中的一个怪物,小兵,我们会在上面加各种特效,又比如新手引导的每一个步骤。
1赞

mark一下

楼主有个问题想请教一下,看了你的这个帖子,我想起来之前做u3d资源优化的时候的一些事情,举例来说:正如楼主所说,
“资源A可能依赖资源B、C、D,而资源D又依赖资源E,这是非常常见的一种资源依赖情况,如果我们使用cc.loader.loadRes(“A”)加载资源A,B~E都会被加载进来,但如果我们调用cc.loader.release(“A”)则只有资源A被释放。”
对于这种问题,在U3D那边常用的采取的方式就是,比如一个预制件A,只引用A预制件自己的图集,音效,纹理等资源,如果真的有特殊的需要,那就做出一个公用的资源(图集、音效、纹理等),因为是公用的资源,所以第一次加载之后,会常驻内存,至于资源A,当预制件A被释放的时候,资源A也进行释放。
包括,我现在在Creator的项目中也是这样做的,加载预制件A的时候,先提前预加载公用资源,等到加载预制件A的时候,只加载预制件A的对应的资源A,当释放预制件A的时候,释放对应的资源A.
综上所述 我的意思就是,如果前期做好资源管理,是不是就可以避免楼主所说的这种问题。还请不吝赐教

宝爷,我是否可以理解为?加载的时候标记资源,使用的时候也标记资源,释放的时候根据标记规则检测该资源是够能够释放?意思就是和c++一样,都封装成中间层方法使用,而不是js中的直接赋值;例如: sprite.spriteFrame = frame 改为 func(sprite, spriteFrame),然后在func中对资源进行规则标记吗 ?

mark一下

差不太多,如果在我们的应用场景中,这个范围内对该资源的使用都是同一生命周期的,当要释放的时候会全部释放,这种情况可以直接赋值,没有必要增加无谓的use。
另外func的参数应该是(node, url),如果是spriteFrame的话,还需要映射spriteFrame到其对应资源的url,因为这里对资源的管理是基于url的。

Unity的AssetBundle跟这里的情况其实不大一样,AssetBundle是你自己规划的打包,什么资源打包到一起,如何组织依赖关系,这个是一个资源规划的问题,我们希望通过合理的打包,起到节约包体和内存的作用。

当时写过一篇AssetBundle的文章 https://www.cnblogs.com/ybgame/p/3973177.html
现在的Unity好像在AssetBundle这块做了很大的重构,我也没有去了解最新的状况是怎样子的。

在这里其实ResLoader内部已经处理好了这种情况了。什么时候应该释放?这里内建了资源引用计数来解决,当没有其它地方用到的情况下,释放A会自动把BCDE都释放掉。

这种思路也可以应用到Unity的AssetBundle中,如果现在还需要我们来规划打包,执行加载和卸载,这个方法可以使卸载更加自动化一些。

好的,我实践一下,另外想请教一下楼主,有没有靠谱严谨一些的关于Creator这方面的资料啊,网上看了很多,感觉大部分都是那种你抄我的我抄你的,说来说去也没说出个所以然:sweat_smile:

少打了几个字 是关于“Creator资源管理”

有一篇意识到这个资源管理问题的文章:《猎头专家》动态资源加载与释放技巧 https://blog.zengrong.net/post/youshootfirst3/
另外也可以看看我之前写的一系列Creator资源底层的分析文章 https://www.cnblogs.com/ybgame/p/10576884.html

1赞

好的 谢谢,我去拜读一下