提出如題所示的問題,心里非常別扭,但的確是事實。因此,Cocos Studio(我目前使用的是 2.3.2)在許多方面還有改進的地方,包括與之相對應的cocos2d-x中的代碼操作部分。
問題
目前,我的試驗結果發現,使用cocos2d-x 3.8.1中提供的如下方法:
1 | ArmatureDataManager::getInstance()->addArmatureFileInfo(filename); |
無法正常加載Cocos Studio 2.3.2導出的骨骼動畫資源文件。例如如下代碼無法正常通過項目構建:
1 | ArmatureDataManager::getInstance()->addArmatureFileInfo( "DemoPlayer.csb" ); |
令人遺憾的例子
盡管如此,但是cocos2d-x 3.8.1的cpp-tests實例中的確提供了使用addArmatureFileInfo方法加載.csb骨骼動畫文件的例子??!
是的,因為.csb文件是二進制格式,目前還找不到其反編譯工具,但是,從使用簡單的工具分析,cpp-tests實例中提供的示例.csb骨骼動畫文件的版本與Cocos Studio 2.3.2導出的骨骼動畫資源文件.csb并不一致。
下面給出Notepad++觀察到的結果圖的對照(第1張是Cocos Studio 2.3.2導出骨骼動畫文件DemoPlayer.csb查看結果,顯然版本號是2.1.0.0,第2張是cpp-tests實例中提供的示例Cowboy.csb骨骼動畫文件查看結果,顯然版本號是1.0.1):


為了進一步分析上述問題,我還專門把cocos2d-x 3.8.1的cpp-tests實例中提供的使用addArmatureFileInfo方法加載其提供的相應.csb骨骼動畫文件的代碼復制到一個簡單示例工程中進行測試,的確OK。相關代碼如下所示:
1234567891011 | const char * HelloWorld::m_binaryFilesNames[4] = { "bear.csb" , "horse.csb" , "Cowboy.csb" , "ccc.csb" }; const char * HelloWorld::m_armatureNames[4] = { "bear" , "horse" , "Cowboy" , "Skeleton1" }; ArmatureDataManager::getInstance()->addArmatureFileInfo(m_binaryFilesNames[3]); Armature *m_armature = Armature::create(m_armatureNames[3]); m_armature->getAnimation()->playWithIndex(0); m_armature->setScale(1.0f); Size size = Director::getInstance()->getWinSize(); m_armature->setPosition(size.width/2, size.height/2); addChild(m_armature); |
對于數組中相應的前三個.csb文件(應該是老版本的STUDIO導出的骨骼動畫csb文件),運行上述代碼非常順利(當然,上述addArmatureFileInfo方法調用更早的ExportJson骨骼動畫文件的情況也是能夠順利運行)。事實上,cpp-tests自然也已經在我的機器上順序調試通過(我的環境是Windows 7 64bits Visual Studio 2013)。但是,對于最后那個csb文件(使用當前新版本Cocos Studio 2.3.2導出的骨骼動畫文件),則根本不行,執行中斷停止在addArmatureFileInfo調用的下一行。
在經過部分的源碼跟蹤后,我嘗試著使用碎圖技術生成csb文件,盡量使之與cpp-tests提供的文件形式上一致,結果也根本通不過!
太遺憾了,我就是想使用Armature及相應的如下技術:
1 | armature->getAnimation()->setMovementEventCallFunc(CC_CALLBACK_0(TestAnimationEvent::animationEvent, this , std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); |
但是,很遺憾,只能干瞪眼!沒有Armature,我們根本無法使用setMovementEventCallFunc回調函數及其相應技術了。
遺憾的是,對于上述問題,官方網站上及DEMO中只字未提!
變通辦法
對于我目前的程序中的上述要求,我只能嘗試著其他的變通方法,因為我的要求也并不高。于是我嘗試著使用幀事件方法解決了上述問題。
在此,我粘貼上我的示例游戲中的相關代碼。
第一部分如下:
1234567891011121314151617 | Node* node2 = CSLoader::createNode( "SplashAnimationSkeleton.csb" ); addChild(node2); node2->setPosition(Vec2(VisibleRect::center().x, VisibleRect::center().y)); ActionTimeline* action2 = CSLoader::createTimeline( "SplashAnimationSkeleton.csb" ); node2->runAction(action2); action2->gotoFrameAndPlay(0, false ); action2->setFrameEventCallFunc(CC_CALLBACK_1(SplashScene::onFrameEvent, this )); |
注意,上面的SplashAnimationSkeleton.csb是使用cocos studio 2.3.2創建的簡單的骨骼動畫文件。
我原先設計的使用setMovementEventCallFunc方法結合Armature數據想實現的是目標是:當骨骼動畫播放結束,觸發另一個既定事件,并在這個事件中完成另外的動畫播放任務。
對于上述目標,使用幀事件應該是可以的,只是稍微麻煩一些罷了。例如,需要在studio設計器中填寫幀事件數據;但是,總算還可以實現。
另外一部分相關代碼如下:
12345678910111213141516171819202122 | void SplashScene::onFrameEvent(Frame* frame) { EventFrame* evnt = dynamic_cast <EventFrame*>(frame); if (!evnt) return ; std::string str = evnt->getEvent(); if (str == "lastFrame" ) { Node* butterfly_01 = CSLoader::createNode( "ButterflyArmature_01.csb" ); addChild(butterfly_01,100); butterfly_01->setPosition(Vec2(VisibleRect::right().x + 100, 0)); ActionTimeline* action2 = CSLoader::createTimeline( "ButterflyArmature_01.csb" ); butterfly_01->runAction(action2); action2->gotoFrameAndPlay(0, true ); Node* p1 = _rootLayer->getChildByName( "Mushroom_Point" ); auto action = Sequence::create( MoveTo::create(2, p1->getPosition()), CallFunc::create(CC_CALLBACK_0(SplashScene::callback0, this )), nullptr); butterfly_01->runAction(action); } } |
大家看到,我在幀事件回調函數中進行判斷,當動畫播放到特定幀時(正是我以前要求的第一個動畫播放結束時)觸發另一個蝴蝶飛入動畫的播放。
小結一下
通過學習與研究部分cocos2d-x 及cocos studio最新版本技術可以學習到更優秀的開發技術的同時,注定我要犧牲許多時間去“踏坑”,也許有得就有失吧。
最后,再提醒一下新手同學,示例工程中的代碼部分與資源數據文件部分都有些不太明確的調用,當然,看起來官方是要盡量使用最新的c++代碼來使用(或者說保護)早期studio導出的資源。但在同時,卻露出了不少急于求成的“馬腳”。
登錄樂搏學院官網http://www.learnbo.com/
或關注我們的官方微博微信,還有更多驚喜哦~

本文出自 “青峰” 博客,請務必保留此出處http://zhuxianzhong.blog.51cto.com/157061/1713824