spine实现预加载(一)
前言
本文实现了spine动画的预加载,解决在战斗等大量加载spine动画的时候出现卡顿现象。
这里使用和修改三个类,直接修改的源码,当然你也可以继承LuaSkeletonAnimation,自己封装一个类。这里做个例子,
不自己写类,直接改源码。如果想自己写,绑定到lua,看我别的帖子。废话不多说,入主题。
在之前对图片 应该对图片进行异步加载,详细以后再说。
版本:quicklua 3.3 win vs2012
原理
先分析下,LuaSkeletonAnimation类
class LuaSkeletonAnimation: public spine::SkeletonAnimation { public: static LuaSkeletonAnimation* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1); LuaSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale = 1); virtual ~LuaSkeletonAnimation(); };
LuaSkeletonAnimation 继承自 SkeletonAnimation类。
在lua_cocos2dx_spine_manual.cpp中可以看到,在lua层调用 create 方法实际是 调用的LuaSkeletonAnimation的 createWithFile 方法
所以我们把新的方法也放到这里,当然你也可以直接放到SkeletonAnimation类中。建议在此处。
再看下SkeletonAnimation类:
static SkeletonAnimation* createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false); static SkeletonAnimation* createWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); static SkeletonAnimation* createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
创建spine动画有两种方法,分别是createwithfile和createwithdata。
createWithFile是通过加载动作数据马上进行创建,如果spine动画中的json文件大小超过100k时,会出现卡顿现象,如果动画文件偏小,可以使用这个方法来创建动画。createWithData是通过预加载,保存动画数据在spSkeletonData中,然后通过实现创建动画。
上面这些我相信你们一看就懂吧。 总体来讲:
lua 层使用,createwithfile 方法创建,然后保存在table 中,实现预加载 。在使用的时候使用createWithData,创建动画。
createWithData方法需要的参数是spSkeletonData,我们需要封装一个获取spSkeletonData的方法,具体看LuaSkeletonAnimation的爷爷类。
c++代码的修改
(1)SkeletonAnimation.h:
spSkeletonData* getSkeletonData();
SkeletonAnimation.cpp 实现
spSkeletonData* SkeletonAnimation::getSkeletonData(){ spSkeletonData*skData =SkeletonRenderer::getSkeleton()->data; return skData; }
(2)LuaSkeletonAnimation.h
class LuaSkeletonAnimation: public spine::SkeletonAnimation { public: static LuaSkeletonAnimation* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1); // preload spine 添加下面两个方法 static LuaSkeletonAnimation* createWithSkeletonAnimation(SkeletonAnimation* skeletonAnimation); LuaSkeletonAnimation(SkeletonAnimation* spineData); LuaSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale = 1); virtual ~LuaSkeletonAnimation(); };
说明:
createWithSkeletonAnimation方法,为了减少导出自定义类,所以参数是 SkeletonAnimation。
LuaSkeletonAnimation::LuaSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale) : spine::SkeletonAnimation(skeletonDataFile, atlasFile, scale) { } LuaSkeletonAnimation::LuaSkeletonAnimation(SkeletonAnimation* spineData) : spine::SkeletonAnimation(spineData->getSkeletonData()) { } LuaSkeletonAnimation::~LuaSkeletonAnimation() { ScriptHandlerMgr::getInstance()->removeObjectAllHandlers((void*)this); } 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::createWithSkeletonAnimation(SkeletonAnimation* skeletonAnimation) { LuaSkeletonAnimation* node = new (std::nothrow) LuaSkeletonAnimation(skeletonAnimation); node->autorelease(); return node; }
改好上面两个类。可以使用cocos2dx自带的脚本重新tolua一下。这里 直接改代码吧,省时有效。。。嘎嘎、、
lua_cocos2dx_spine_manual.cpp
1.
static int lua_cocos2dx_CCSkeletonAnimation_createWithSkeletonAnimation(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) { //TODO SkeletonAnimation* skeletonAnimation = (SkeletonAnimation*)tolua_tousertype(L, 2, 0); auto tolua_ret = LuaSkeletonAnimation::createWithSkeletonAnimation(skeletonAnimation); 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; } #if COCOS2D_DEBUG >= 1 tolua_lerror: tolua_error(L,"#ferror in function 'createWithSkeletonAnimation'.",&tolua_err); #endif return 0; }
2.static void extendCCSkeletonAnimation(lua_State* L)方法中添加一行:
tolua_function(L, "createWithSkeletonAnimation", lua_cocos2dx_CCSkeletonAnimation_createWithSkeletonAnimation);
lua使用及预加载
上面代码改好之后,编译一下,跑起来程序,在lua测试一下,能不能正常调用函数。OK的话,就可以写代码 预加载了。
在项目中我们一般要有个loadlayer 吧需要的音乐 图片 spine等预加载进去。这里测试一下就不写了、
首先我们要封装一下 sp.SkeletonAnimation
local SpineNode = class("SpineNode", function(spineName) spineName = "ceshi" --预加载列表有,就直接使用 if LoadingManager:isSpineLoad(spineName) then dump("****************preload:"..spineName) do return sp.SkeletonAnimation:createWithSkeletonAnimation(LoadingManager.preloadSpines[spineName]) end end if not cc.FileUtils:getInstance():isFileExist(spineName..".json") then print("Ani ERROR: not found " .. spineName .. "\n") print(debug.traceback("", 2)) spineName = "ceshi" end local s_pPathSpineBoyJson = spineName..".json" local s_pPathSpineBoyAtlas = spineName..".atlas" return sp.SkeletonAnimation:create(s_pPathSpineBoyJson, s_pPathSpineBoyAtlas, 1) end)
其他需要 的方法自己封装几个。这里不写了。
在整个统一的预加载资源类 ,提前加载spine 等,就可以了。
注释:
可以使用 createWithData ,添加一个 getAnimationData的方法。原理是一样的。
以后会追加一篇关于lua异步加载 spine图片的文章。
追加:
先create 一个母本,在添加到缓存数组的时候,记得retain一下。最后记得释放release。
要不然创建母本之后,会自己释放掉,导致直接崩溃。
总结
兄弟们那,一定要多看源码啊。。。流程应该很清晰了吧、。、、少年们应该能看懂了。交流加我QQ776274781 。大神勿喷。。