使用DragonBones开发FLASH骨骼动画入门教程
轉自:使用DragonBones開發FLASH骨骼動畫入門教程
本文轉載(并略作修改)自黃竣的教程,URL是:http://dragonbones.github.com/getting_started_cn.html全文如下:
DragonBones是什么?
DragonBones是一套開源的 2D骨骼動畫框架和工具,它包含了基于Flash Pro的骨骼動畫編輯面板Skeleton Animation Design Panel及骨骼動畫ActionScript框架。
它可以讓開發者運用熟悉的Flash Pro元件及時間軸編輯方式,快速創建2D骨骼動畫,并運用到Flash或其他技術的應用中。
【朱先忠注】?Flash2Cocos2d-x正是由RainyNote(博客地址是:http://rainynote.com/2012/09/cocos2d-x-%E5%8A%A8%E7%94%BB%E5%B7%A5%E5%85%B7/)開發出的直接操作FLASH骨骼動畫及其相關文件的coco2d-x擴展框架。
Features
-
動畫基于Flash pro時間軸,可以使用Flash傳統動畫方式制作游戲動畫;
-
骨骼綁定可以讓動畫更精準,更真實自然,并可通過程序動態控制;
-
可設置單個骨骼的動畫時間縮放和延時播放,使用較少的關鍵幀就可以表現復雜生動的動畫效果;
-
動畫各部分采用拼接方式,動畫有緩動補間,占用位圖/內存資源少;
-
骨骼顯示對象與骨骼的邏輯分離,可在不影響動畫播放的情況下動態更換;
-
能方便用于傳統DisplayList、Starling及其他技術的2D應用。
下載與安裝設置
開源項目地址:http://dragonbones.github.com
-
從這兒獲取Adobe Flash Pro 5.5或以上版本
-
下載最新的DragonBones release 包,安裝支持Flash Pro的骨骼面板擴展插件SkeletonDesignPanel.zxp (注:此插件目前僅支持Flash Pro5.5及以上版本), 獲取骨骼動畫ActionScript庫SkeletonAnimationLibrary。
- 在后續的教程中,我們將使用這套框架來動態顯示由Flash Pro設計的骨骼動畫。
教程源碼下載
接下來,我們將通過幾個簡單的教程快速了解DragonBones的用法。
請從這里下載本教程相關源碼。
教程1:針對設計師 使用DragonBones在Flash Pro中創建骨骼動畫
作為設計師,你只需要準備好動畫角色的各個部分,在Flash Pro的時間軸中把他們有序組裝起來、設置好動作關鍵幀并運用DragonBones的骨骼動畫編輯面板搞定一切。
在下載并安裝完畢骨骼面板的Flash Pro擴展插件后,啟動Flash Pro。打開教程源碼下載包中的DragonBones_tutorial_Start.fla文件。
打開庫面板,你可以看到此示例的相關資源。
在parts目錄中包含的是組成動畫Dragon的各個元件,從命名可以直觀的了解到它們對應的龍的各個部分。良好的元件命名是個好習慣,不是么?:)
雙擊庫面板中的MovieClip元件Dragon進入時間軸編輯模式。我們需要詳細了解這個動畫的組成,它有助于后面骨骼動畫編輯。
注意:1,請留意時間軸上的各層的命名,我們是以骨骼各個部分來命名的。骨骼動畫面板將自動根據層的命名來識別組成骨骼的各個部分。
,2,需要注意的是層label,我們添加了標簽“walk”用來說明當前時間軸表示的動作。如果由多個動作,請在對應動作起始位置添加標簽來說明。這一步非常重要!骨骼動畫面板將按照標簽來讀取并設定動作。你發現時間軸上并沒有添加補間?是的,你僅僅需要在時間軸上設置關鍵幀上各元件的位置,剩下的工作都可以在骨骼面板中完成。
當然,作為設計師的你,可以按你的習慣做好完整的補間動畫,骨骼面板同樣可以按照你的動畫原樣導入。(注:目前版本的DragonBones僅支持傳統補間,新補間將在后續版本中支持)
當你按上述要求準備好動畫,就可以點擊Flash Pro菜單中的Window>Other Panels>SkeletonAnimationDesignPanel打開骨骼動畫編輯面板。我們將在接下來的操作中詳細說明骨骼動畫編輯面板的使用。
在此面板中點擊“Import”按鈕,此時將出現下圖所示窗口:
在導入面板中你可以設置貼圖排序、貼圖高度及貼圖間距。在導入選項中,你可以導入選中的庫元件、所有庫元件以及通過骨骼面板導出的PNG/SWF/ZIP文件等。
選中Flash Pro庫中的MovieClip元件Dragon,然后在骨骼動畫編輯面板中選擇導入選中的項目,點擊OK按鈕。
骨骼動畫編輯面板導入動畫元件Dragon后如下圖:
Armature List: 導入動畫MovieClip的列表,與MovieClip在庫中的名稱一致,程序中將以此名稱來創建動畫對象。每個包含動作的MovieClip,在DragonBones里我們稱之為“骨架”(Armature)。
Behavior. List: 對應動畫對象的各個動作/行為名稱,與MovieClip中幀標簽名稱一致,程序中將以此名稱來動態播放各種動作。
Bone Tree: 動畫對象的各個骨骼組成部分,與MovieClip中各層名稱一致。
Texture List: 動畫對象中各部分對應的材質名稱。
對于每個動作,首先要設置的參數如下:
Total Frame: 當前動作的總幀數。幀數越大,動作越慢。
Tween Frame: 設置其他動作切換到此動作需要的幀數。比如,你的游戲角色有個動作為蹲下,此動作在時間軸上僅有1幀。假如設置此參數為6,那么當游戲中從其他動作切換到蹲下時候,程序會自動增加6幀的過渡,讓各個動作切換更加自然。
Keyframe. Ease: 當前動作各關鍵幀之間的緩動系數。
Loop: 當前動作是否循環播放。比如角色的走、跑步等。
A當設置好上述參數,你可以在左下方的預覽區域中看到當前編輯動作的動畫。
預覽窗口左上角可以縮放預覽對象,便于觀察的動作。
OK,接下來我們在Bone Tree面板中設置動作中各個骨骼的從屬關系。下圖可以看到在默認導入的動畫中,各個骨骼沒有關聯:
在此面板中右上角的 可以設置在預覽窗口里當前選中骨骼的高亮顏色。
在列表里我們可以拖拽的方式,將子骨骼附著在父骨骼上。如下圖,我們將身體設置為主骨骼,而頭、尾巴、上肢和下肢都為其子骨骼。而上肢中又包含了上臂、下臂和手等。通過樹形結構我們可以非常直觀的看到他們的從屬關系。
我們可以對每個骨骼的運動參數進行單獨設置。在Bone Tree面板中選中你需要設置的骨骼,調節下列參數。
Tween Time Scale: 設置當前骨骼運動時間相對動作總時間(總幀數)的增加或減少。
Tween Time Delay: 設置當前骨骼開始運動時間相對所屬動作的延遲或提前。
別小看這2個參數,各個骨骼通過這2個參數微調后,你會發現角色動作哪怕在時間軸上僅有2個關鍵幀,也會產生非常復雜的動作。
例如本例中,我們把龍的尾巴tail的Tween Delay設置為-10,尾巴尖tailTip的Tween Delay設置為-50,你可以明顯看到尾巴隨著身體的運動甩動起來,非常的生動。;)
當你調整完骨骼動畫,就可以點擊”Export”按鈕導出。
在導出格式選項中,包含多種數據格式供你實際項目需求。
- SWF (XML Merged): 包含骨骼XML數據的SWF格式,如果游戲需要矢量的骨骼動畫可以采用此格式導出,當然前提是原始素材都是矢量的。
- PNG(XML Merged): 包含骨骼XML數據的PNG格式。
- Zip(XML and SWF): 分開保存的骨骼XML數據和SWF資源。
- Zip(XML and PNG): 分開保存的骨骼XML數據和PNG圖片。
- Zip(XML and PNGs): 分開保存的骨骼XML數據和按每個骨骼獨立的PNG圖片包。
例如在本例中,我們選擇PNG(XML Merged),點擊OK導出文件DragonWalk.png到指定的目錄。
你會發現導出的就一個PNG文件?是的,我們選擇了合并XML數據的PNG格式,所以此文件中包含了骨骼動畫需要的所有數據。
作為設計師,到此你的工作圓滿完成。
朱先忠注:
接下來,我們所需要了解的是,研究中的COCOS2D-X示例代碼,以便使用C++把上述FLASH數據呈現于你的COCOS2D-X游戲中。
因此,下面的內容僅僅參考。
教程2:針對程序開發 在ActionSript項目中應用骨骼動畫
在設計師用骨骼動畫編輯面板導出好相關格式數據之后,程序開發者就可以運用DragonBones的開源動畫框架將數據資源導入到程序并讓動畫角色運動起來。只需幾步操作,非常簡單!
接下來,你將了解如何在傳統DisplayList或支持GPU加速的Starling框架中調用骨骼動畫。
下載Skeleton Animation Framework,將這個包導入至你的開發項目中。
在開始代碼前,讓我們了解下骨骼動畫框架的基本概念。
Factory: 這是構建骨骼動畫的基礎。它負責從前面骨骼面板導出的資源中解析數據格式和準備圖像資源,并且通過它創建骨骼容器Armature。
Armature: 我們可以把它想像為一個容器,它對應在Flash Pro中編輯并通過骨骼面板導出的一個MoiveClip。通過Armature來對各骨骼進行管理,播放動畫等。
現在我們來看看在在傳統DisplayList顯示模式中添加骨骼的示例。打開此教程對應的源文件DB_Tutorial_Walk_DisplayList.as。
首先,將骨骼面板導出的資源嵌入到項目。
?| [Embed(source = "../assets/Dragon1.swf", mimeType = "application/octet-stream")]? private static const ResourcesData:Class; |
此處嵌入的資源是由Flash Pro骨骼動畫編輯面板導出的合并了XML數據文件的PNG文件或SWF文件。當然,你也可以通過動態加載的方式在項目運行時候實時載入資源。
創建factory,并通過fromRawData方法解析載入的資源格式,當解析完畢后交給對應事件textureCompleteHandler處理。
?| factory = new BaseFactory(); factory.addEventListener(Event.COMPLETE, textureCompleteHandler); factory.parseData(new ResourcesData()); |
事件函數textureCompleteHandler中,首先用buildArmature方法構建骨骼動畫容器:
?| armature = factory.buildArmature("Dragon"); |
然后將容器的顯示內容armature.display添加到場景:
?| addChild(armature.display as Sprite); |
指定要播放骨骼的某個動作:
?| armature.animation.play("walk"); |
最后,為ENTER_FRAME事件函數中添加armature.update()方法,讓SWF每幀渲染時候更新骨骼動畫。
OK,僅此幾行代碼,你就可以將骨骼動畫添加到已有項目。很簡單,不是么?:)
下面我們聊聊在Starling中添加骨骼動畫的方法。Starling是一個非常不錯的開源游戲框架,它可以幫助你快速創建基于Stage 3D技術GPU加速的2D游戲。如果你對它還不了解,請訪問Starling的官方網站:http://starlingframework.org。
使用Starling的用戶或許對用Sprite Sheet的位圖序列來構建動畫非常熟悉,這種方式最大問題是對于復雜動畫會占用過多內存。以下圖為例,一個簡單的行走動作,就會占用一大張位圖材質。
而DragonBones解決了這個問題,不但僅需要少量骨骼素材,而且可以讓動畫更加豐富生動。
DragonBones可以完美的結合Starling,創建基于GPU加速的2D骨骼動畫。
打開本示例的項目DBStarlingWalk.as源碼你會發現,我們創建了一個基于Starling的factory:
| factory = new StarlingFactory(); |
而余下的代碼,跟上個DisplayList的示例代碼完全一致。
關于Starling中嵌入的骨骼動畫素材資源,可以是合并骨骼XML數據的PNG格 式,也可以是合并XML數據的SWF格式。對于SWF格式的矢量資源,Skeleton Animation Framework會自動在程序運行時轉換矢量為位圖材質,節省你項目尺寸。?
教程3:創建并控制多個動作的骨骼動畫
接下來你將了解到運用DragonBones創建包含多個動作的骨骼動畫,并在程序中通過鍵盤交互控制動作。
打開文件 DragonBones_Tutorial_MultiBehavior.fla,雙擊庫里的動畫元件Dragon,你可以看到此動畫中有四個動 作:stand,walk,jump和fail。每個動作的起始幀上添加了對應的幀標簽,這也是DragonBones識別不同動作的標識。
打開骨骼動畫編輯面板,你會看到在Behavior. List里面會有多個動作,選擇某個動作就可以為對應動作設置動畫幀數、緩動,設置此動作的某個骨骼的細節參數等。
請留意Behavior編輯里的Tween Frame選項。
這個選項是表明的其他動作切換到當前動作需要的過渡幀數。例如這里設置 的跳躍動作的Tween Frame為3,那么其他動作切換到跳躍需要3幀,DragonBones框架會自動為你添加其中的過渡幀,讓各種動作之間切換變得自然。當然,你可以在 動畫預覽窗口中看到各種動畫的切換效果。
調整完畢各個動作的細節后,點擊“Export”按鈕導出骨骼動畫數據。
打開DBStarlingMultiBehavior.as文件,代碼如下。此示例是在Starling框架中通過鍵盤控制骨骼動畫運動。
?| package { ????import dragonBones.Armature; ????import dragonBones.factorys.StarlingFactory; ????? ????import flash.ui.Keyboard; ????? ????import starling.display.Sprite; ????import starling.events.EnterFrameEvent; ????import starling.events.KeyboardEvent; ????import starling.text.TextField; ????? ????? ????public class DBStarlingMultiBehavior. extends Sprite ????{ ????????[Embed(source = "../assets/Dragon2.png", mimeType = "application/octet-stream")] ????????public static const ResourcesData:Class; ????????? ????????private var factory:StarlingFactory; ????????private var armature:Armature; ????????private var armatureClip:Sprite; ? ????????private var isLeft:Boolean; ????????private var isRight:Boolean; ????????private var isJumping:Boolean; ????????private var moveDir:int=0; ????????private var speedX:Number = 0; ????????private var speedY:Number = 0; ????????private var textField:TextField ????????? ????????public function DBStarlingMultiBehavior() ????????{ ????????????factory = new StarlingFactory(); ????????????factory.addEventListener(Event.COMPLETE, textureCompleteHandler); ????????????factory.parseData(new ResourcesData()); ? ????????} ????????? ????????private function textureCompleteHandler():void ????????{ ????????????armature = factory.buildArmature("Dragon"); ????????????armatureClip = armature.display as Sprite; ????????????armatureClip.x = 400; ????????????armatureClip.y = 550; ????????????addChild(armatureClip); ????????????updateBehavior() ????????????addEventListener(EnterFrameEvent.ENTER_FRAME, onEnterFrameHandler); ? ????????????stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyEventHandler); ????????????stage.addEventListener(KeyboardEvent.KEY_UP, onKeyEventHandler); ????????????? ????????????textField=new TextField(400,30,"A-move left,D-move right,W-jump","Verdana",16,0,true) ????????????textField.x=60; ????????????textField.y=2; ????????????addChild(textField); ????????} ????????? ????????private function onKeyEventHandler(e:KeyboardEvent):void ????????{ ????????????switch (e.keyCode) ????????????{ ????????????????case Keyboard.A : ????????????????case Keyboard.LEFT : ????????????????????isLeft=e.type == KeyboardEvent.KEY_DOWN; ????????????????????break; ????????????????case Keyboard.D : ????????????????case Keyboard.RIGHT : ????????????????????isRight=e.type == KeyboardEvent.KEY_DOWN; ????????????????????break; ????????????????case Keyboard.W : ????????????????case Keyboard.UP : ????????????????????jump(); ????????????????????break; ????????????} ????????????var dir:int; ????????????if (isLeft && isRight) ????????????{ ????????????????dir=moveDir; ????????????????return; ????????????} ????????????else if (isLeft) ????????????{ ????????????????dir=-1; ????????????} ????????????else if (isRight) ????????????{ ????????????????dir=1; ????????????} ????????????else ????????????{ ????????????????dir=0; ????????????} ????????????if(dir==moveDir) ????????????{ ????????????????return; ????????????} ????????????else ????????????{ ????????????????moveDir=dir; ????????????} ????????????updateBehavior() ????????} ????? ????????private function onEnterFrameHandler(_e:EnterFrameEvent):void ????????{ ????????????updateMove(); ????????????armature.update(); ????????} ? ????????private function updateBehavior():void ????????{ ????????????if (isJumping) ????????????{ ????????????????return; ????????????} ????????????if (moveDir == 0) ????????????{ ????????????????speedX = 0; ????????????????armature.animation.gotoAndPlay("stand"); ????????????} ????????????else ????????????{ ????????????????speedX=6*moveDir; ????????????????armatureClip.scaleX = -moveDir; ????????????????armature.animation.gotoAndPlay("walk"); ????????????} ????????} ????????private function updateMove():void ????????{ ????????????if (speedX != 0) ????????????{ ????????????????armatureClip.x += speedX; ????????????????if (armatureClip.x < 0) ????????????????{ ????????????????????armatureClip.x = 0; ????????????????} ????????????????else if (armatureClip.x > 800) ????????????????{ ????????????????????armatureClip.x = 800; ????????????????} ????????????} ????????????if (isJumping) ????????????{ ????????????????if (speedY <= 0 && speedY + 1 > 0 ) ????????????????{ ????????????????????armature.animation.gotoAndPlay("fall"); ????????????????} ????????????????speedY += 1; ????????????} ????????????if (speedY != 0) ????????????{ ????????????????armatureClip.y += speedY; ????????????????if (armatureClip.y > 540) ????????????????{ ????????????????????armatureClip.y = 550; ????????????????????isJumping = false; ????????????????????speedY = 0; ????????????????????updateBehavior(); ????????????????} ????????????} ????????} ????????private function jump():void ????????{ ????????????if (isJumping) ????????????{ ????????????????return; ????????????} ????????????speedY = -25; ????????????isJumping = true; ????????????armature.animation.gotoAndPlay("jump"); ????????} ????} } |
通過上面的代碼我們可以發現,我們只需要在程序中需要播放相關骨骼動畫的時候調用函數armature.animation.gotoAndPlay()即可。
除了指定需要播放的動作名稱,你還可以通過此函數來動態指定動作的總幀數、是否循環等。
對于每個動畫,除了指定其播放之外,DragonBones框架提供了動畫播放相關的各種事件。
動作切換事件:
?| armature.addEventListener(dragonbones.events.Event.MOVEMENT_CHANGE, aramtureEventHandler); |
動作開始事件:
?| armature.addEventListener(dragonbones.events.Event.START, aramtureEventHandler); |
動作結束事件
?| armature.addEventListener(dragonbones.events.Event.COMPLETE, aramtureEventHandler); |
動作循環完畢事件:
?| armature.addEventListener(dragonbones.events.Event.LOOP_COMPLETE, aramtureEventHandler); |
通過各種事件與動作的配合,你可以輕松創建具有復雜運動角色的游戲。?
控制骨骼框架中的每根骨頭
對于一個有趣的游戲,僅僅播放預先設置的骨骼動畫或許不夠,我們需要角色具有動態可控的各自動作。令人高興的是DragonBones提供了訪問并控制骨骼框架里每根骨頭的方法,讓你的角色在游戲中隨意運動。
此示例通過鼠標在場景中的移動來控制骨骼。我們創建了一個跟隨鼠標運動的小鳥,小龍人會與小鳥保持一定距離,同時小龍人的頭和胳膊會跟隨小鳥運動而做出不同姿勢,非常有趣。
打開DBStarlingControlBone.as,代碼如下。
?| package { ????import dragonBones.Armature; ????import dragonBones.Bone; ????import dragonBones.factorys.StarlingFactory; ????? ????import flash.geom.Point; ????import flash.ui.Mouse; ????? ????import starling.display.Image; ????import starling.display.Sprite; ????import starling.events.EnterFrameEvent; ????import starling.events.TouchEvent; ????import starling.textures.Texture; ????? ????? ????public class DBStarlingControlBone extends Sprite ????{ ????????[Embed(source = "../assets/Dragon2.png", mimeType = "application/octet-stream")] ????????public static const ResourcesData:Class; ????????? ????????[Embed(source = "../assets/starling.png")] ????????private static const starlingImg:Class; ????????? ????????private var factory:StarlingFactory; ????????private var armature:Armature; ????????private var armatureClip:Sprite; ????????? ????????private var mouseX:Number = 0; ????????private var mouseY:Number = 0; ????????private var moveDir:int=0; ????????private var dist:Number; ????????private var speedX:Number = 0; ????????private var starlingBird:Image; ????????private var _r:Number; ????????? ????????private var _head:Bone; ????????private var _armR:Bone; ????????private var _armL:Bone; ????????? ????????public function DBStarlingControlBone() ????????{ ????????????factory = new StarlingFactory(); ????????????factory.addEventListener(Event.COMPLETE, textureCompleteHandler); ????????????factory.parseData(new ResourcesData()); ????????} ????????private function textureCompleteHandler():void ????????{ ????????????armature = factory.buildArmature("Dragon"); ????????????armatureClip = armature.display as Sprite; ????????????? ????????????armatureClip.x = 400; ????????????armatureClip.y = 550; ????????????addChild(armatureClip); ????????????updateBehavior(0) ????????????addEventListener(EnterFrameEvent.ENTER_FRAME, onEnterFrameHandler); ????????????stage.addEventListener(TouchEvent.TOUCH, onMouseMoveHandler); ????????????? ????????????starlingBird=new Image(Texture.fromBitmap(new starlingImg())) ????????????addChild(starlingBird); ????????????Mouse.hide(); ????????????//get the bones which you want to control ????????????_head = armature.getBone("head"); ????????????_armR = armature.getBone("armUpperR"); ????????????_armL = armature.getBone("armUpperL"); ????????????? ????????} ????????? ????????private function onEnterFrameHandler(_e:EnterFrameEvent):void ????????{ ????????????checkDist(); ????????????updateMove(); ????????????updateBones(); ????????????armature.update();????? ????????} ????????? ????????private function checkDist():void ????????{ ????????????dist = armatureClip.x-mouseX; ????????????if(dist<150) ????????????{ ????????????????updateBehavior(1) ????????????} ????????????else if(dist>190) ????????????{ ????????????????updateBehavior(-1) ????????????} ????????????else ????????????{ ????????????????updateBehavior(0) ????????????} ????????????? ????????} ????????? ????????private function onMouseMoveHandler(_e:TouchEvent):void ????????{ ????????????var _p:Point = _e.getTouch(stage).getLocation(stage); ????????????mouseX = _p.x; ????????????mouseY = _p.y; ????????????starlingBird.x=mouseX-73; ????????????starlingBird.y=mouseY-73; ????????} ????????private function updateBehavior(dir:int):void ????????{ ????????????if(moveDir==dir)return; ????????????moveDir=dir; ????????????if (moveDir == 0) ????????????{ ????????????????speedX = 0; ????????????????armature.animation.gotoAndPlay("stand"); ????????????} ????????????else ????????????{ ????????????????speedX=6*moveDir; ????????????????armature.animation.gotoAndPlay("walk"); ????????????} ????????} ????????private function updateMove():void ????????{ ????????????if (speedX != 0) ????????????{ ????????????????armatureClip.x += speedX; ????????????????if (armatureClip.x < 0) ????????????????{ ????????????????????armatureClip.x = 0; ????????????????} ????????????????else if (armatureClip.x > 800) ????????????????{ ????????????????????armatureClip.x = 800; ????????????????} ????????????} ????????} ????????private function updateBones():void ????????{ ????????????//update the bones' pos or rotation ????????????_r = Math.PI + Math.atan2(mouseY - armatureClip.y+armatureClip.height/2, ??????????????????????????????????????mouseX - armatureClip.x); ????????????if (_r > Math.PI) ????????????{ ????????????????_r -= Math.PI * 2; ????????????} ????????????_head.node.rotation = _r*0.3??????? ????????????_armR.node.rotation = _r *0.8; ????????????_armL.node.rotation = _r * 1.5; ????????????? ????????????starlingBird.rotation = _r*0.2; ????????} ????} } |
從上面代碼我們可以看到,通過方法dragonBones.Armature.getBone(_name:String):Bone來獲取某個骨骼。骨骼中的node對象包含了此骨骼的位置坐標,旋轉弧度,拉伸比例,傾斜數據等等。我們根據游戲邏輯的需要對骨骼的這些參數賦數,即可實現動態控制此骨骼的效果。
在上面示例中,請留意updateBones()函數里,我們先獲取到當前鼠標位置與骨骼框架中心點的夾角,然后根據這個角度,來改變小龍人的頭部和胳膊的旋轉弧度,從而實現了這個有趣的效果。
實現骨骼動畫換裝
在游戲中我們往往有這樣的需求:角色更換服飾、裝備或武器等。對于DragonBones來說,所謂的換裝可以通過更換對應骨骼的材質來輕松實現。
因為是更換骨骼的材質,所以我們可以在程序中動態創建新材質并賦予對應骨骼,新的材質可 以是來自其他方式創建或加載的圖片,也可以來自DragonBones骨骼動畫編輯面板導出的材質圖集(Texture Atlas)。或許你會問,如何在Flash Pro中把沒有預先放在動畫時間軸的材質一起打包在骨骼動畫編輯面板導出的材質圖集中呢?
打開本教程的示例文件DragonBones_Tutorial_ChangeClothes.fla 。這個文件中,我們把動畫元件Dragon穿上了一件黃馬褂,將其放在時間軸上名為clothes的層上,并調整符合各種動作。
然后請注意庫中的clothTextureTemp動畫元件,雙擊打開 它,你會發現我們把打算換裝的4件衣服放在時間軸不同層上,并分別將層名稱與其對應。這4件衣服因為大小形狀一樣,所以在層中重合了。不過實際項目中,很 多時候更換的衣服、武器或道具大小不盡相同,所以需要相對于骨骼動畫中原始服飾的位置調整好各自坐標位置。
留意在層label上我們給第一幀的幀標簽取名為temp。因為沒有幀標簽的動畫元件,是不會被骨骼動畫編輯面板識別導入的。
選中庫中的Dragon和clothTextureTemp兩個元件, 打開骨骼動畫編輯面板,點擊“Import”按鈕導入所選的元件,你會發現在面板中Armature List里有了一個名為clothTextureTemp的骨架并且包含clothes1至clothes4的骨骼。不用管它,我們將它們導入面板的目的 不是為了編輯骨骼動畫,僅僅是為了最終導出這些服裝材質與骨骼動畫材質到一個文件中。
接下來你只需對Dragon這個骨架進行相關的骨骼動畫調整,然后點擊”Export”按鈕導出素材資源。這里我們導出為合并XML數據的DragonWithClothes.png 。你會發現導出的材質圖集中包含了我們需要的各自衣服。:)
現在我們看看在程序中如何實現換裝。打開教程3中創建的DBStarlingMultiBehavior.as文件,我們直接在這個文件中添加換裝代碼即可。首先將嵌入的素材更改為DragonWithClothes.png:
?| [Embed(source = "../assets/DragonWithClothes.png", mimeType = "application/octet-stream")] |
然后添加2個變量,數組textures保存了我們要更換服裝材質的名稱,整數textureIndex用來做切換材質時候的索引。
?| private var textures:Array = ["parts/clothes1", "parts/clothes2", "parts/clothes3", "parts/clothes4"]; private var textureIndex:int = 0; |
請注意這里寫的是“parts/clothes1”而不是 “clothes1”,原因是Flash Pro的庫中不同目錄的元件名稱可以相同,所以DragonBones在保存資源路徑的時候也包含了目錄結構。打開 DragonBones_Tutorial_ChangeClothes.fla看看庫里的衣服動畫元件所在的目錄你就明白了。:)
在鍵盤響應函數onKeyEventHandler中添加下面代碼,這樣按下鍵盤C鍵的時候調用換裝函數。
?| case Keyboard.C: ????if (e.type == KeyboardEvent.KEY_UP) { ????????changeClothes(); ????} ????break; |
創建換裝函數changeClothes()如下:
?| private function changeClothes():void { ????//循環更換貼圖 ????textureIndex++; ????if (textureIndex >= textures.length) { ????????textureIndex = textureIndex - textures.length; ????} ????//從骨骼面板導出的textureData中獲取Image實例,也可以單獨從其他圖片文件中構造Image ????var _textureName:String = textures[textureIndex]; ????var _image:Image = StarlingFactory.getTextureDisplay(factory.textureData, _textureName); ????//用image替換bone.display完成換裝(注意bone.display的回收) ????var _bone:Bone = armature.getBone("clothes"); _bone.display.dispose(); ????_bone.display = _image; } |
這里我們用到了 dragonBones.factorys.StarlingFactory.getTextureDisplay(_textureData:TextureData, _fullName:String):Image來獲取由骨骼動畫編輯面板導出的材質數據,然后將對應的材質賦予給骨骼的display對象,實現了換 裝。當然,正如前面所說,換裝的材質可以隨意來自程序中載入的其他圖片資源。
W另外,當你熟悉了DragonBones的開源框架,你會發現可以通過代碼實現更加靈活的變換,除了更換骨骼材質,你還可以在骨骼框架(Armature)中動態的刪除、添加骨骼,改變骨骼的從屬關系等。
OK,到此你掌握了如何在DragonBones中為你的游戲角色換裝,趕緊在你的游戲中試試吧。:)
總結
以上是生活随笔為你收集整理的使用DragonBones开发FLASH骨骼动画入门教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 春节没事,看几部黑客电影吧!
- 下一篇: 有线数字电视机顶盒的基本原理