1. 程式人生 > >Spine的使用 With Cocos2d-x

Spine的使用 With Cocos2d-x

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

Spine的使用(With Cocos2d-x)

Spine是一個2D的骨骼動畫編輯器, 因為其良好的UI設計及完整的功能, 在kickstarter上釋出以後立即收到追捧, 作為一個幾乎只有遊戲開發者才會使用的小眾工具, 募集了遠超目標5倍的資金, 共計6.7W多美元. 我在其專案釋出後, 成為了Spine在kickstarter的早一批backer, 這是我在kickstarter上第一個, 也是目前唯一一個支援的專案. 隨後, 通過不斷收到的郵件見證了Spine逐步完善的過程, 直到其發出target完成的郵件. 又過了這麼長時間了, 因為手頭的專案一直不需要太複雜的2D骨骼動畫, 拖著沒有研究, 現在也是時候看看Spine了, 可惜的是, Spine的使用還有一系列的

視訊教學可以參考, 而Spine的Runtime使用完全沒有文件, 只有一兩個簡單的例子. Spine團隊的主要精力目前還是放在一些新功能的開發和Runtime的繼續支援上, 寫文件還排在Next up上.

目錄:

Runtime使用

簡單的迴圈動畫

編輯上看視訊教程吧, 只是打包檔案需要使用TexturePacker的libgdx的Data Format來匯出, 字尾改為atlas.

然後, 從例子中能學到的東西:

  1. new CCSkeletonAnimation("test.json", "test.atlas");來建立想要的Spine動畫物件.
  2. CCSkeletonAnimationsetAnimation("anim_name", true);來設定想要的動畫.
  3. 需要將CCSkeletonAnimation物件按node一樣處理, 用addChild介面新增到parent node上. 並且物件可以當作普通的Node一樣來操作, 因為它實際就繼承自CCNodeRGBA.

比如在一個node中, 按如下程式碼可以建立一個spineboy行走的動畫, 並且迴圈播放.

skeletonNode = new CCSkeletonAnimation("spineboy.json", "spineboy.atlas");skeletonNode->setAnimation("walk", true);CCSize windowSize = CCDirector::sharedDirector()->getWinSize();skeletonNode->setPosition(ccp(windowSize.width / 2, 20));addChild(skeletonNode);skeletonNode->release();

播放一次動畫

簡單的情況, 播放一次動畫後就不管了, 那麼直接使用CCSkeletonAnimation::setAnimation, 並且以false為第二個引數就好了.

更復雜的情況, 需要知道什麼時候這個動畫播放完了, 因為Spine的Runtime中沒有動畫結束的回撥(這是另外一種良好的設計), 只能通過在update中判斷. 更進一步的悲劇是, 在cocos2d-x的Runtime中中沒有簡單的判斷方法, example中給了一個方法:

if (skeletonNode->states[0]->loop) {    if (skeletonNode->states[0]->time > 2) skeletonNode->setAnimation("jump", false);} else {    if (skeletonNode->states[0]->time > 1) skeletonNode->setAnimation("walk", true);}

這裡使用的方法是判斷播放時間, 我對此方法表示強烈的反感, 也絕對的建議大家不要使用, 因為你不僅需要預先知道每個動畫播放的時長, 而且任何時候你改動了動畫的播放時間, 這個程式碼都得回來改, 這樣做根本就違反我們使用編輯器的初衷, 甚至我覺得在Runtime的example中給出這種程式碼是非常不負責任的行為. 這個方法只在一種情況下使用, 那就是你的確是想要在某個動畫播放的確定時間幹某個事情, 不過這種情況應該非常少見.

在的確需要知道播放完一次動畫時, 我建議用以下方式來完成, 因為沒有現成的C++介面, 這裡借用了一個C程式碼中的函式來完成工作:

if(AnimationState_isComplete(skeletonNode->states[0])) {    if ( 0 == strcmp(skeletonNode->states[0]->animation->name, "walk") ) {        skeletonNode->setAnimation("jump", false);    }    else {        skeletonNode->setAnimation("walk", false);    }}

連續播放動畫

上面那個例子中的動畫連續動畫播放可以直接通過CCSkeletonAnimation::addAnimation介面來完成, 這樣更加簡單.

skeletonNode = new CCSkeletonAnimation("spineboy.json", "spineboy.atlas");skeletonNode->addAnimation("walk", false);skeletonNode->addAnimation("jump", false);skeletonNode->addAnimation("walk", true);

但是失去了一些靈活性, 並且, Spine還不支援將多個動畫接起來作為一個完整的動畫使用, 這個挺弱的, 再加上Spine工具本身就沒有連線多個動畫的功能, 就更加弱了.

程式控制的骨骼動畫

所謂程式控制的骨骼動畫, 就是類似Spine宣傳動畫中那樣, Globin的目光跟隨著滑鼠的移動. 這個功能的實現, 應該算是骨骼動畫中最酷的一部分了. 傳統的序列幀動畫完全無法實現, 要實現的話還是得在序列幀外拆分肢體, 然後單獨實現.

在骨骼動畫中, 可以直接取到骨骼, 然後調整骨骼, 實現這樣的效果, 要方便很多. 在Spine中取得骨骼的函式是CCSkeletonAnimation::findBone, 其他的就是設定rotation就行了.

void ExampleLayer::ccTouchesMoved(CCSet *touches, CCEvent *event) {    CCTouch* touch = (CCTouch*)touches->anyObject();    CCPoint pos = touch->getLocation();    Bone* head = skeletonNode->findBone("head");    CC_ASSERT(head != nullptr);    float tanValue = (pos.y - head->worldY) / (pos.x - head->worldX);    float rotation = atan(tanValue) * 180 / 3.1415;    head->rotation = rotation;}

需要注意的是, 動畫本身要是在播放的話, 不能動這個骨骼(被parent牽引是OK的), 不然的話會被動畫本身強制改變, 看不到touch帶來的效果.

其他功能

慢動作和快動作

設定CCSkeletonAnimation的timeScale值.

動畫混合

對於一般情況下, 動畫的切換要求兩個動畫完全能銜接上, 不然會出現跳躍感, 這個對於美術來說要求很高, 而Spine加了個動畫混合的功能來解決這個問題. 使得不要求兩個動畫能完全的銜接上.

比如上面的walk和jump動畫, 就是銜接不上的, 直接按上面的辦法切換, 會出現跳躍, 但是加了混合後, 看起來就很自然了. 哪怕放慢10倍速度觀察, 也完美無缺. 這個功能在序列幀動畫時是無法實現的, 也是最體現Spine價值的一個功能. 程式碼如下:

skeletonNode->setMix("walk", "jump", 0.3f);skeletonNode->setMix("jump", "walk", 0.3f);

問題

Spine的出現, 對於2D骨骼動畫編輯工具來說, 絕對是翻天覆地的變化, 劃時代的. 這也再次說明了自己的問題, 因為和以前的同事說了很久了, 其實我們需要一個這樣的編輯器, 但是自己卻從來沒有寫過一個-_-! 當然, 我們當時討論的是做一個開源的. 但是, Spine畢竟剛剛出現, 其實還是有不少的問題. 如下:

工具使用上

  1. 體驗上, 因為Spine用了JAVA來實現偷懶的跨平臺, 很多地方都弱爆了, 奇怪的menu就不說了, 那檔案對話方塊難用的要死, 在Mac下, 會覺得那檔案對話方塊簡直就是折磨人, 不管是選對一個資料夾, 還是儲存檔案到一個地方, 都能讓人很鬱悶. 還能出現原介面被阻塞, 而檔案對話方塊被擋住的情況. 假如要一套程式碼的跨平臺通用, 那就沒有使用者體驗可言. 當然, 其實Spine本身對動畫編輯方面的體驗還是非常棒的.
  2. 功能上, Spine不支援像cocos builder一樣直接讀取pack後的材質, 只能讀原始的材質, 這個有些弱, 導致需要在原始資源上進行編輯. 這個在工程管理上沒有直接讀取打包後的材質方便. 假如打包出了什麼問題, 這裡也看不見.
  3. 還是功能上, Spine在編輯器中無法直接連線多個動畫, 這個功能連cocos builder中都有.
  4. 雖然Spine有個用example做UI的演示, 但是實際上因為Spine沒有任何地方可以設定點選響應和設定變數繫結, 這個基本上也就是隻能做做UI上面的動畫.
  5. 這個和Runtime也有關, Spine的擴充套件性幾乎沒有, 連想自定義一個引數都沒有辦法, 比如我想用Spine來設定一個Bone的旋轉的上限和下限, 也無法做到.

Runtime的問題

Spine的Runtime有些太馬虎了, 問題相當多.

  1. 沒有詳細的文件就算了, 甚至連程式碼的註釋生成文件都沒有. 同時代碼的註釋也少的可憐, 根本就不像一個嚴謹的開源專案. 更進一步, 連example都只有1個, 要是不知道該怎麼用, 哭去吧. 這個只能說Spine還不夠成熟, 一般來說, 像這種程度的東西, 最好別用.
  2. 為了讓一套程式碼能夠儘量支援多的引擎, 有些地方太偷懶了. 對此吐槽的也不止我一個, 比如這裡的A call for coders to build a better Spine runtime for Cocos2D, 就算是C++使用者, 用這簡單從C wrap過來的runtime我都感覺非常難受, 更加別說objc的使用者了.
  3. 最大的問題是Spine用了一套字尾為atlas的資原始檔, 但是這根本不是cocos2d/cocos2d-x的使用方式, 我們要的是plist! 所以Spine用到的資源會和Cocos2d-x中用到的資源格格不入, 無法統一管理和cache. 這種問題使得Spine幾乎不可用, 因為一個稍微想點樣子的遊戲, 也不能容忍每個動畫都是在需要播放的時候再載入資源.
    這個問題有個解決方案, 就是不用example中使用的CCSkeletonAnimation建立介面CCSkeletonAnimation::CCSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale), 而是使用CCSkeletonAnimation::CCSkeletonAnimation (const char* skeletonDataFile, Atlas* atlas, float scale)這個介面, 並且自己首先快取Atlas檔案. 或者, 直接快取所有可能出現的skeletonNode物件. 只是, 這些解決方法都太麻煩並且不夠優美. 並且, 還是沒有辦法和cocos2d-x原有的資源統一管理.

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述