小屋創作

日誌2017-05-13 22:09

Cocos2d-x DragonBones 製作骨骼動畫 實現換裝效果

作者:Majitoo

前言:
不知不覺專題已經製作了9個月了
我們的角色動畫起初是使用Cocos Studio編輯器內建的骨骼動畫
摸索了一陣子也做出來創角選單,並實現換裝效果,影片如下
於是有位巴友n653b447 介紹了一款叫做龍骨(DragonBones)的骨骼動畫編輯器
龍骨(DragonBones)官網
不過當初已經把Cocos Studio的換裝程式碼研究好了,就沒再深入研究了
後來專題負責美術動畫的組員抱怨說Cocos Studio的骨骼動畫不太好用
自己嘗試做了一下,也發覺真的很難用,而且問題超多,會有一些莫名其妙的問題
一怒之下,就跑去研究龍骨(DragonBones)
以下是龍骨能做出來的效果
哇~竟然能把一張照片弄得栩栩如生(5分17秒處)
於是去找了一下如何把龍骨用進Cocos2d-x裡



龍骨Cocos2d-x C++運行庫配置教學:

第一步:
官方有提供一個庫專門給Cocos2d-x使用
https://github.com/DragonBones/DragonBonesCPP
首先從gitHub上面下載下來
裡面有3rdParty  Cocos2DX_3.x  DragonBones三個資料夾
點開DragonBones/src,有個dragonBones資料夾
把這個dragonBones丢進你的cocos2d-x專案下的Classes

第二步:
回到從gitHub上下載的三個資料夾地方
點開Cocos2DX_3.x/src/dragonBones,有個cocos2dx資料夾
把這個cocos2dx資料夾丟進,第一步驟末的dragonBones資料夾裡。
如圖  test 是我Cocos2d-x專案名稱:


第三步:
回到從gitHub上下載的三個資料夾地方
點開3rdParty裡面分別有rapidjson和rapidxml
把這兩個資料夾複製到cocos2d專案下
並且把rapidjson改名為json。
原因是dragonBones的Json解析庫
和cocos2d-x內建的Json解析庫,互相衝突
也可以說dragonBones上的Json解析庫是擴充版
因此我們要把cocos2d-x內建的Json庫給刪除
但是cocos2d-x引擎中,也有其他文件已經引用了原本內建庫
大部分都是#include "json\document.h"
所以我們把Classes下的rapidjson改名為json
這樣就不用再去更改其他文件的include路徑
(後面會再詳細說明)


第四步驟:
回到從gitHub上下載的三個資料夾地方
點開Cocos2DX_3.x/Demos 裡面有Classes 和 Resources
很熟悉對巴,沒錯。這兩個就直接丟進Cocos2d-x專案下就好
顧名思義Classes裡面的程式,就是Cocos2d-x使用龍骨的範例
而Resources下就是龍骨產生的資源檔案。
所以最終路徑會是這樣
(黑色塗掉部分是我的測試程式)


第五步驟:
打開visual studio把所有專案下所有Classes丟進裡面

運行專案會出現錯誤
error C2039: 'GetFloat': 不是 'rapidjson::GenericValue<rapidjson::UTF8<char>,
rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>>' 的成員

會出現這個原因就是上面所提到的現在專案中有兩個Json解析庫
一個是GitHub上運行庫所附帶的
另一個是Cocos2d-x本身內建的
因此來教大家如何刪除Cocos2d-x內建Json庫

第六步驟:
首先進到Cocos2d專案底下的資料夾(test是我Cocos2d的專案名)

把這個json資料夾給刪除
再到visual studio依照圖片路徑,刪除rapidjson資料夾

這樣就就刪除cocos2d-x內建的Json解析庫了
這時編譯器馬上報錯

提示說找不到json解析庫
因為在一個方案中有很多專案
我們主要是在test專案寫程式

libcocos2d專案就是引擎源代碼的部分
上面的抱錯都是在libcoco2d專案內的引擎代碼抱錯
所以我們要讓libcocos2d專案知道我們新的解析json庫的位子

第七步驟:
對libcocos2d專案點擊右鍵>屬性>C/C++>一般>其他Include目錄添加一行
$(EngineRoot)..\Classes
這個就是我們放新的解析Json庫的路徑
可以看下方評估值
順帶一提路徑中的  
.. 就是上一頁的意思
.  就是當前頁面

添加完後,就會發現錯誤少了許多
可能剩下幾個錯誤,確認一下是否include到新的Json解析庫就行了
如果出現#include "json/filestream.h"
這行可以刪掉
到這邊運行專案應該就沒有問題了!
如果還是有錯誤嘗試rebuild看看

成功的話,會跑出很炫的機器人Demo
這個Demo真的很酷,趕緊拿去編譯成APK
想看看手機上運行的效果
才突然想到要設定那個Android.mk
Classes裡面那麼多檔案,我要把每個cpp都寫進去也太累?!
此時我想起在一開始從gitHub下載的資料夾內路徑
Cocos2DX_3.x\src\dragonBones\proj.android
裡面有已經打好的內容,只是路徑不太正確需要修改一下

這是我修改後的內容
https://github.com/jimmyy512/test/blob/master/Android.mk
第17行../../Classes/Test.cpp \
這行可以刪除掉,這是我做測試時用的
Android.mk放進Cocos2d-x專案下的\proj.android\jni裡
此時就可以嘗試編譯APK了
但是卻出現以下錯誤

錯誤提示說找不到這個header檔,畢竟我們把舊有的json解析庫給刪掉了
NDK並不知道,我們新的json解析庫的路徑位子
我們知道/cocos2d/cocos/.\editor-support/cocostudio/DictionaryHelper.h 是在這個路徑下出錯
因此去這個路徑下,會看到一個android.mk
打開來後下方有一行
LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. \
                                           $(LOCAL_PATH)/WidgetReader
我們要告知NDK,新的Json路徑
改成如下
LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. \
                                           $(LOCAL_PATH)/WidgetReader\
                                           $(LOCAL_PATH)/../../../../Classes
寫新的一行時記得要加上斜線

再次編譯會發現這資料夾有再繼續編譯了,不然之前是直接出錯
但接著編譯到其他資料夾時,又會發生相同的錯誤
問題和解決方法的方法都一樣
都是去針對android.mk裡的LOCAL_C_INCLUDES 去添加路徑
我整理了一下需要改的路徑有這些
---------------------------------------------------------------------------------------------------
E:\work3.12\LegendStory\cocos2d\cocos\editor-support\cocostudio\android.mk
$(LOCAL_PATH)/../../../../Classes
---------------------------------------------------------------------------------------------------
E:\work3.12\LegendStory\cocos2d\cocos\3d\cocostudio\android.mk
$(LOCAL_PATH)/../../../Classes
---------------------------------------------------------------------------------------------------
E:\work3.12\LegendStory\cocos2d\extensions\cocostudio\android.mk
$(LOCAL_PATH)/../../Classes
---------------------------------------------------------------------------------------------------
E:\work3.12\LegendStory\cocos2d\cocos\network\cocostudio\android.mk
$(LOCAL_PATH)/../../../Classes
---------------------------------------------------------------------------------------------------
到這邊為止,編譯APK就成功了


基本麻煩的東西都搞好了,就是來好好學習龍骨這個軟體如何操作
龍骨官方有錄製好一系列教學
https://www.youtube.com/watch?v=njaTTLCx6aY&list=PLAxFOjtO8N8MnN29EIv_0bHauzqCjW93A
很不錯的影片,我看完後對龍骨的操作,有一定程度上的熟悉
於是我利用之前做Cocos studio的角色素材做了個動畫
並且嘗試做出換裝效果但是在做輸出檔案時

請記得選取4.5版,目前只支援4.5的。
GitHub已更新,目前以支持5.0數據
輸出後會有三個檔案,分別是
test_ske.json
test_tex.json
test_tex.png
放進專案Resources下後
Cocos2d-x可以寫代碼來進行撥放動畫
  1. dragonBonesData = _factory.loadDragonBonesData("test_ske.json");
  2. _factory.loadTextureAtlasData("test_tex.json");
  3. _armatureDisplay = _factory.buildArmatureDisplay("MainCharacter");
  4. _armature = _armatureDisplay->getArmature();
  5. _armatureDisplay->setPosition(180, 0);
  6. _armatureDisplay->getAnimation().play("Idle", -1);
  7. dragonBones::WorldClock::clock.add(_armature);
  8. this->addChild(_armatureDisplay);
第一 第二行 分別載入資源
第三行是載入專案中的骨骼
和Cocos Studio不同的是,龍骨中的骨骼動畫能在嵌套另一個骨骼動畫
譬如一開始的Cocos studio換裝影片,角色並不會眨眼
而利用龍骨,我就能做到
表情做一套骨骼動畫,產生出眨眼、動態的表情
頭髮做一套骨骼動畫,產生出長髮飄逸的感覺
武器做一套骨骼動畫,武器會發出微微閃光、火焰特效
衣服做一套骨骼動畫,衣服隨風飄逸......等等
下面是在Cocos2d-x實際跑的效果:
我自己試做了一次,跑步途中自動切換武器
這張圖主要是展現出骨骼動畫能在嵌套另一個骨骼動畫
身體動作是一個骨骼動畫
臉部表情也是一個骨骼動畫
武器特效也是一個骨骼動畫
倘若請專業的美術人員來做,角色是可以做的活靈活現的



第三行所加載動畫就是專案中很多骨骼動畫的其中一個
龍骨右下角有資源列表,MainCharacter就是我主要的骨骼動畫
所以第三行去做加載的動作
_armatureDisplay是CCArmatureDisplay的指針變數
CCArmatureDisplay是繼承於cocos2d::Node
所以自然也可以setPosition,也需要addChild 加入到場景中
第六行則利用_armatureDisplay去撥放 製作好的動畫 -1代表無限循環
第七行  WorldClock以下為官方文檔中的解釋
WorldClock 提供時鐘的支持,為控制每個加入時鐘的 IAnimatable 對象正確的播放動畫。一般來說,每當 Armature 被創建出來後,只需要將之加入 WorldClock,之後只需要控制 WorldClock 的前進,就可以實現所有 Armature 的動畫前進了

這八行程式就能完整在場景上跑一個動畫了!
接著時如何實現換裝的效果
就我所知有四種換裝方法


第一種 (內部換裝)


在龍骨中,每個骨骼下都有個插槽,插槽下可以有很多張圖片
例如我這邊有一個Head骨骼  骨骼下有一個Face插槽和一個Head插槽
Head插槽下,分別有Head和Head2分別是兩張不同的頭型
我一選到Head2 頭型就變了
(Face插槽和Head插槽小圖示不一樣,是因為Face插槽是骨骼動畫)


這些都是我在龍骨上進行的操作
那在程式上要如何操作呢?很簡單!
_armature->getSlot("Head")->_setDisplayIndex(0);
_setDisplayIndex參數傳入0,插槽就會替換成Head圖片
或是
_armature->getSlot("Head")->_setDisplayIndex(1);
_setDisplayIndex參數傳入1,插槽就會替換成Head2圖片
_armature就是骨骼 getSlot就是獲取插槽名


第二種 (內部骨骼動畫中的換裝)

前面說了骨骼動畫中,能再嵌套骨骼動畫
如圖專案中有一個Sword骨骼,骨骼裡面有個Sword骨骼插槽
而底下資源列表也有一個人型圖示的Sword
資源列表中的人型圖示,就是專案其他的骨骼動畫
上方Sword骨骼插槽,就是從下方資源列表中的Sword的骨骼動畫拉上來的
那這邊為甚麼又要放一個骨骼動畫呢?

因為我可以利用這個Sword骨骼動畫,單純對劍做一些特效
例如劍上有火焰,劍又會反光等等
但是遊戲中又不可能只有一把劍
所以Sword骨骼動畫中,我又放了另外兩把外型不同的劍

那回歸MainCharacter骨骼動畫
該如何切換(Sword)骨骼動畫中的不同的劍呢?

首先獲取Sword插槽底下的Sword骨骼動畫(人型小圖示)
auto _SwordArmature =_armature->getSlot("Sword")->getChildArmature();
接著就能利用_setDisplayIndex來切換武器摟!
_SwordArmature->getSlot("sword")->_setDisplayIndex(1);
我有三把武器所以_setDisplayIndex()能傳入的數字就0,1,2
分別就是第一把武器,第二把武器及第三把武器


第三種 (切換內部骨骼動畫)


前面第二種換裝主要是切換骨骼動畫中的圖片
那這個是切換骨骼Sword下的Sword插槽中的不同骨骼動畫
資源列表中有Sword1骨骼動畫和Sword2骨骼動畫
所以用這行程式就可以達到切換不同的骨骼動畫!
_armature->getSlot("Sword")->setChildArmature(_factory.buildArmature("Sword1"));
或是
_armature->getSlot("Sword")->setChildArmature(_factory.buildArmature("Sword2"));


第四種 外部換裝
前面都是預先把圖片資源放進龍骨裡,再利用_setDisplayIndex()函數來達到切換的效果
那如果是後來 在cocos2dx 才加載的圖片呢?
Sprite* newSword = Sprite::create("sword1.png");
_armature->getSlot("sword")->setDisplay(newSword , dragonBones::DisplayType::Image);
就可以達成效果

第五種
factory.replaceSlotDisplay(
"任意龍骨工程名", "任意骨架名", "任意插槽名", "任意圖片名", "任意插槽");
意思就是:
將任意龍骨工程裡的任意骨架裡的任意插槽裡的任意圖片替換到任意插槽上。

總結:
//內部換裝
_armature->getSlot("Head")->_setDisplayIndex(0);

//內部換裝 切換插槽內的子骨骼動畫,並且替換骨骼動畫中的圖片
auto _SwordArmature = _armature->getSlot("Sword")->getChildArmature();
_SwordArmature->getSlot("sword")->_setDisplayIndex(1);

//內部換裝 切換插槽內不同的骨骼動畫
_armature->getSlot("Sword")-setChildArmature(_factory.buildArmature("Sword1"));

//外部換裝 資源是放在外部的,並不是一開始就放在龍骨裡的
Sprite* newHead = Sprite::create("Head1.png");
_armature->getSlot("Head")->setDisplay(newHead, dragonBones::DisplayType::Image);


以上就是我目前的一些心得,只摸了幾天
未來實際應用到專題中
有甚麼心得時,會再補上

更新文章心得:
-------------------------------------------------20170517更新-------------------------------------------------------
已在文中更新了有關
error C2039: 'GetFloat': 不是 'rapidjson::GenericValue<rapidjson::UTF8<char>...得錯誤
-----------------------------------------------------------------------------
在我一開始寫這篇文章時,本來都沒出現這錯誤
過幾天後,我嘗試把DragonBonesC++運行庫放進專題的專案中
準備取代CocosStudio的骨骼動畫
但卻出現這奇怪錯誤,於是我寫了信問官方團隊

接著官方回信

於是我嘗試刪除了cocos2dx自帶的json解析庫
接著運行就出現錯誤

我真的很討厭遇到這種無法解析的問題,因為通常這種錯誤不好找
只好又在寄信問問官方
官方回信說這種問題通常是庫的引用出了問題,實在不行嘗試 rebuild

我抱著心灰意冷的心態去rebuild,首先呢rebuild專案要跑很久...
第二,rebuild完,問題通常都不會解決。
但沒想到rebuild完,竟然完美運行!!!
也算是個蠻奇特的經驗

如果是照著我文章去操作的話,應該是不需要去rebuild的
我那時候會出錯,可能是因為當時我改引擎改太多東西,才需要rebuild的


-------------------------------------------------20170522更新-------------------------------------------------------
已在文中更新了有關,再刪除內建的Json解析庫後
NDK編譯時,找不到Json解析庫路徑所產生的錯誤
fatal error: 'rapidjson\document.h' file not found
-----------------------------------------------------------------------------

1

1

LINE 分享

相關創作

C++學習日誌:猜數字

工作轉換領域一年後的心情抒發

[達人專欄] [ OpenGL 入門到入土 # 2] Compute shader、GPU Instance、DrawIndirect與實作Frustum culling

留言

開啟 APP

face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】