项目背景

项目使用unity做游戏,并使用addressables方案管理资源,基于spine作为很多unity的骨骼动画实现方案,在我们的项目中有一些不合理的地方:

  1. 使用ScriptableObject作为桥接SkeletonDataUnity的方案,导致skel文件在加载完成之后不会卸载,这导致Spine动画很多的情况下会导致很多的Native资源占用;
  2. Spine动画使用的地方很多,但是大部分时候只会播放一个动画;

为此我们实现了两个Spine方案上的改动:

  1. SkeletonData加载完成之后手动卸载skel.bytes文件;
  2. 按照动画名字拆分Spine文件中的动画,按需加载Spine动画文件;

下面是具体实现

spine资源卸载

该功能主要是针对skel文件加载完成之后不回收的问题

SkeletonDataAsset作为桥接SpineUnity的承载类,主要是指定使用的Spine资源,这些资源直接使用unity的引用关系关联,加载SkeletonDataAsset的时候会自动将关联的资源加载进入内存,读取完成之后没有卸载对应的资源,导致部分TextAsset资源开销浪费:
思路很简单,本身SkeletonDataAsset方法都是通过GetSkeletonData方法获得SkeletonData实例,这里面回去调用SkeletonBinary读取数据,这里可以缓存读过的SkeletonData实例,判断首次读取之后手动销毁Skel TextAsset 文件. 这部分不会减少单独加载spine的峰值内存,但是实际运行时能减少很多的native内存.

按需加载Spine动画

该部分并不通用,需要你的动画没有手动设置过渡效果以及不会出现动态加载spine的情况

由于项目中基本不会运行时加载Spine组件,而是加载spine组件时候通过代码控制播放的动画,因此劫持了Animation中的Timeline过程,在编辑器里面将Skel 文件拆分成头部和动画部分,懒加载Animations的部分内容,从而降低运行开销.

感想

通用库的开发会有很多的考量,适用性相较于部分的性能可能更是他们考虑的重点,对于很多库进行项目适应的调整是很有必要的。