Quick-Cocos2d-x v3.3 异步加载Spine方案 转

Quick-Cocos2d-x v3.3 异步加载Spine方案

浩月难求也与2015-03-25 15:06:3441 次阅读

背景

项目中使用了Quick-Cocos2d-x 3.3,由于Spine各个功能相当强大,所以使用了Spine作为骨骼动画,由于Spine并非cocos官方支持,所以在一些问题上支持性不是那么好,其中如何异步加载Spine就是一个问题。

 

比如游戏中经常遇到这么一个问题:在主战斗场景中,需要加载大量的图片、声音、Spine动画等,如果我们等到需要用到的时候再去加载,由于文件I/O是比较耗时的,有可能就会在游戏过程造成卡顿的现象,尤其在低端配置手机中体现尤为明显,这就会造成游戏体验不佳。

 

对于这个问题呢,一种比较常用的解决方案:在进入主战斗之前,就会预加载所有战斗中需要用到的资源,并且缓存起来,等到真到需要用到游戏资源的时候,直接去读取缓存中的数据,那就是我们经常看到的Loading条。

 

难点

1、异步加载 

Cocos本身已经支持了一些资源的异步加载回调,使用多线程做的,每加载完一个资源,都可以有异步回调作相应的处理(比如显示加载进度)。但是 对于一些cocos官方不支持的资源,比如Spine等,就需要自己实现异步加载回调。

 

自己实现我知道有两种方法:

一种就是和cocos官方的一样,也用多线程做,这个没什么好说的。 

一种就是叫做”同步异步化“,开启一个每帧都update函数,在update()里加载一次资源,用同步的方式实现异步加载的资源。

“同步异步化”在Lua中还有另一种方法可以实现,就是用Lua的协程,更加的方便。

 

我自己使用的是使用的update这种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  function LoadingLayer:update(ts)   -  --- 每帧加载一次资源
     local pngNum = table.nums(ResMng._pngList)
     local plistNum = table.nums(ResMng._plistList)
     local soundNum = table.nums(ResMng._soundList)
     local spineNum = table.nums(ResMng._spineList)
     local curLoadNum = ResMng._curLoadNum
 
     -- 加载资源顺序
     -- 1、加载PNG
     if  0 <= curLoadNum and curLoadNum < pngNum then
         ResMng.loadPng()
 
     -- 2、加载PLIST
     elseif pngNum <= curLoadNum and curLoadNum < pngNum + plistNum then
         ResMng.loadPlist()
 
     -- 3、加载SOUND    
     elseif pngNum + plistNum <= curLoadNum and curLoadNum < pngNum + plistNum + soundNum then
         ResMng.loadSound()
 
     -- 4、加载Spine
     elseif pngNum + plistNum + soundNum <= curLoadNum and curLoadNum < pngNum + plistNum + soundNum + spineNum then
         ResMng.loadSpine()
 
     else
         print( "所有资源预加载完成" )
 
         ResMng.resortSpine()
 
         self:replaceScene()
 
     end 
end

 


2、Spine缓存 

Cocos官方都对一些常用的资源支持了缓存,如TextureCache、AnimationCache、SpirteFrameCache、AudioCache,但是由于Spine并非官方支持,所以对于Spine的缓存需要自己实现,对于Spine缓存实现方式,也有两种方法可以参考: 

1、在C++层,实现一个和官方类似的缓存方案,叫做SpineCache,然后增加tolu层代码,这种方式优雅、自然,但是代价比较大。

2、在Lua层手动实现一个简易的缓存方案。

 

这里我当然是使用的第二种方案了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 加载一次Spine图
function ResMng.loadSpine()
     local spineInfo = self._spineList[self._curLoadIndex]
     assert (spineInfo,  "加载Spine索引出错"  .. self._curLoadIndex)
 
     local spineAnimation = require( "app.common.factory.sp_animation" ). new ()
     spineInfo.animation = spineAnimation:createWithID(spineInfo.id)
     spineInfo.animation:getNode():retain()
 
     self._curLoadNum = self._curLoadNum + 1
     if  self._curLoadIndex == #self._spineList then
         self._curLoadIndex = 1
     else
         self._curLoadIndex = self._curLoadIndex + 1
     end
end
 
-- 从缓存中获取Spine
function ResMng.getSpineByID(spineID)
     -- 如果不存在此资源,先加载到缓存
     if  not self._spineList[spineID] then
         print( "缓存文件:" , spineID)
         local spineAnimation = require( "app.common.factory.sp_animation" ): new ()
         self._spineList[spineID] = spineAnimation:createWithID(spineID)
         self._spineList[spineID]:getNode():retain()
     end
 
     local newSpine = require( "app.common.factory.sp_animation" ): new ()
     return  newSpine:createWithData(self._spineList[spineID])
end

 

 

3、导出createWithData到Lua层调用 

Spine Runtime,加载Spine有两种方式: 

一个是createWithFile, 使用的是文件IO方式,这个相当耗时 

一个是createWithData,使用的是已经加载好的Spine的骨骼数据,这种方法速度比较快。 

但是Quick默认两个方法都不自动导出,都是用的手写代码导出,且只手动导出createWithFile, 如果我们需要使用createWithData,这时就需要手动导出了,导出代码如下: 

LuaSkeletonAnimation.h

1
2
3
4
5
6
7
8
class  LuaSkeletonAnimation:  public  spine::SkeletonAnimation {
public :
     static  LuaSkeletonAnimation* createWithFile ( const  char * skeletonDataFile,  const  char * atlasFile,  float  scale = 1);
     static  LuaSkeletonAnimation* createWithData(SkeletonAnimation* spineData);
     LuaSkeletonAnimation ( const  char * skeletonDataFile,  const  char * atlasFile,  float  scale = 1);
     LuaSkeletonAnimation(SkeletonAnimation* spineData);
     virtual  ~LuaSkeletonAnimation();
};

 

LuaSkeletonAnimation.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
LuaSkeletonAnimation::LuaSkeletonAnimation ( const  char * skeletonDataFile,  const  char * atlasFile,  float  scale)
: spine::SkeletonAnimation(skeletonDataFile, atlasFile, scale)
{
}
LuaSkeletonAnimation::LuaSkeletonAnimation(SkeletonAnimation* spineData)
: spine::SkeletonAnimation(spineData)
{
}
LuaSkeletonAnimation* LuaSkeletonAnimation::createWithFile ( const  char * skeletonDataFile,  const  char * atlasFile,  float  scale)
{
     LuaSkeletonAnimation* node =  new  (std:: nothrow ) LuaSkeletonAnimation(skeletonDataFile, atlasFile, scale);
     node->autorelease();
     return  node;
}
LuaSkeletonAnimation* LuaSkeletonAnimation::createWithData(SkeletonAnimation* spineData)
{
     LuaSkeletonAnimation* node =  new  (std:: nothrow ) LuaSkeletonAnimation(spineData);
     node->autorelease();
     return  node;
}

lua_cocos2dx_spine_manual.cpp

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//add by chenhao on 2015/03/24
//手动添加Spine tolua代码,解决Spine缓存问题 
static  int  lua_cocos2dx_CCSkeletonAnimation_createWithData(lua_State* L)
{
     if  (nullptr == L)
         return  0;
     int  argc = 0;
     # if  COCOS2D_DEBUG >= 1
         tolua_Error tolua_err;
         if  (!tolua_isusertable(L, 1,  "sp.SkeletonAnimation" , 0, &tolua_err))  goto  tolua_lerror;
     #endif
     argc = lua_gettop(L) - 1;
     if  (1 == argc)
     {
     # if  COCOS2D_DEBUG >= 1
         if  (!tolua_isusertable(L, 1,  "sp.SkeletonAnimation" , 0, &tolua_err))
         {
             goto  tolua_lerror;
         }
     #endif
         SkeletonAnimation* spineData = (SkeletonAnimation*)tolua_tousertype(L, 2, 0);
         auto tolua_ret = LuaSkeletonAnimation::createWithData(spineData);
         int  nID = (tolua_ret) ? ( int )tolua_ret->_ID : -1;
         int * pLuaID = (tolua_ret) ? &tolua_ret->_luaID : NULL;
         toluafix_pushusertype_ccobject(L, nID, pLuaID, ( void *)tolua_ret,  "sp.SkeletonAnimation" );
         return  1;
     }
     luaL_error(L,  "'createWithFile' function of SkeletonAnimation has wrong number of arguments: %d, was expecting %d\n" , argc, 2);
     # if  COCOS2D_DEBUG >= 1
         tolua_lerror:
         tolua_error(L,  "#ferror in function 'createWithData'." , &tolua_err);
     #endif
     return  0;
}

并且在extendCCSkeletonAnimation()中,添加下面这行代码。

1
tolua_function(L,  "createWithData" , lua_cocos2dx_CCSkeletonAnimation_createWithData);

为了减少导出自定义类, 我对C++层createWithData的参数类型作了一些修改,但是不影响。改为了:

1
static  SkeletonAnimation* createWithData(SkeletonAnimation* spineData);

以上都是本人自己实现摸索过程中, 探索出来的一些方法,有什么问题大家可以提出来,我好修改

转载于:https://www.cnblogs.com/rexzhao/p/4366229.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值