项目接近尾声,需要做加载效率优化和内存优化。
在加载Spine制作的资源时候,我们需要将文件(.json)进行解析,然后创建对象
spAtlas* t_atlas = spAtlas_createFromFile(altas_name.c_str(), 0); 第一步 //加载纹理文件
spSkeletonJson* json = spSkeletonJson_create(t_atlas); 第二步 //根据上步产生的对象穿件JSON骨架
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, ske_name.c_str()); 第三步 //根据骨架和名称加载骨架数据(真正的骨架)
spSkeletonJson_dispose(json); 第四步 //析构JSON骨架
SkeletonAnimation* t_ani = SkeletonAnimation::createWithData(spSkeletonData* skeletonData); 第五步 //创建对象
有经验的同学,应该知道,必须你程序当中需要10只黄色的小鸡。首先美术人员要通过Spine工具来创建一个黄色小鸡的工程文件,然后程序加载(A),创建10个对象(B)。
注意,每次创建一个小鸡对象的时候,都需要解析文件,然后创建对象。
解析文件(我们暂且叫A)是指:把(.JSON)文件从磁盘加载到内存,上述第一步到第四步,都是在干这件事。这地方,我们自己制作的动作文件,在windows上加载耗时高达2000ms,而在手机上加载达到100ms。手机和PC相差近20倍
根据加载后的数据创建对象(我们暂且叫B)。这地方耗时在PC和手机上基本一致,大概2ms
假设我们不做任何处理,想在PC上创建10只小鸡,那就是
A(2000ms)B(2ms), A(2000ms)B(2ms),A(2000ms)B(2ms), A(2000ms)B(2ms),A(2000ms)B(2ms), A(2000ms)B(2ms),A(2000ms)B(2ms), A(2000ms)B(2ms),A(2000ms)B(2ms), A(2000ms)B(2ms), = 2000*10+2*10 = 20020ms
很显然,我们在解析过程A浪费了大量时间,所以,我们希望的是一次加载,多次创建。这在原理上是可以行的通的。
A(2000ms)B(2ms)B(2ms)B(2ms)B(2ms)B(2ms)B(2ms)B(2ms)B(2ms)B(2ms)B(2ms) = 2000ms + 2*10 = 2020ms
这样,我们的事件可以大幅度降下来。
好了,我们一款游戏当中,肯能有小鸡,小鸭,小猫,小狗,几百种动物。那我们就直接在游戏开始时候,将所有动物的JSON文件都解析加载好。把它交给Loading吧,哈哈。然后在程序实时过程中,动态创建对象,就可以秒创建了。
而且有一点可以肯定的是,骨架文件解析后,占有内存特别小。在游戏中最占内存就是纹理了。所有想优化内存,我们要在纹理上想办法。
遗憾的是,spine的骨架加载完(A步),其实纹理就已经持有并一直存在了,如果想把纹理内存干掉,必须要把加载的骨架(A步的产物)干掉。但是如果把骨架干掉了,在创建对象的时候,可以需要重新加载对应的骨架文件(json),就很耗时了。
那就没办法了,我们既不想反复加载骨架而导致耗时,也不想在不渲染骨骼动画的时候,让纹理占有内存。忘了说一下,PC和手机在加载一张512*512的纹理时候,只需要60ms左右,但是其纹理内存确实有1M。所以,我们就想能不能再渲染前加纹理加载到内存,然后在使用完毕后,在将纹理内存卸载掉。
比如从主场景,进入战斗,需要加载技能特效,这些纹理,需要在使用时候加载,然后退出战斗就卸载掉。如果有频繁的操作,可以做纹理cache。本着这个目的,我们想怎么去改spine来达到这个目的呢。
改库很容易出现各种各样的错误和内存泄露,首先,我们必须要了解库的结构。然后在能从中做最小的最安全的修改来达到我们的目的。
这篇有点长,下边分析spine的数据结构