木匣子

Web/Game/Programming/Life etc.

用 DragonBones for Cocos2d-x 实现帧动画

本文所使用的 Cocos2d-x 和 Cocos2d-html5 版本均为 2.2.2

美术组对骨骼动画提出了一个需求,希望能用 DragonBones 实现定格效果,而不是每帧都自动产生补间。

经过一翻搜索,我在这里找到了一个方法,只需要在骨骼的关键帧上使用 ^ 标签就可以取消骨骼动画的补间。实际上 DragonBones 的 wiki 上就有这么一行说明,被我略过了。

疑问

不过,虽然这个方法确实能在 DragonBones 插件的预览窗中看到定格动画的效果,但导出到 Cocos2d-x 或 Cocos2d-html5 中时,依然还是有补间动画。

阅读了 Cocos2d-html5 的源码后,我发现了问题所在:

/extensions/CocoStudio/Armatrue/utils/CCDataReaderHelper.js

ccs.CONST_A_TWEEN_FRAME = "tweenFrame";

ccs.DataReaderHelper.decodeFrame = function (frameXML, parentFrameXml, boneData, dataInfo) {
    // ...
    var isTween = frameXML.getAttribute(ccs.CONST_A_TWEEN_FRAME) || true;
    frameData.isTween = Boolean(isTween);
    // ...
}

当解析 DragonBones 导出的 xml 文件时,判断是否补间,它读的是 tweenFrame 字段,然而 xml 没有这个字段:

DragonBones 使用的则是 twE 来表达补间缓动,一般情况下是 -1 到 +1,没有补间时为 NaN

此外,这段程序有一处不明显的逻辑BUG。即使 xml 存在 tweenFrame,且为 “0” 时:
Boolean("0") 仍然为 true,于是这成了永真式。

这是 javascript 的一个坑:

> "0" == false  
> Boolean(0) == false  
> Boolean("") == false  
> Boolean("0") == true  
> Boolean("false") == true

修改插件

知道问题的所在后,从何改起?对于 cocos2d-x / cocos2d-html5 为何不读 twE 而是读 tweenFrame 我的了解不多,或许是为了兼容 CocoStudio。

若是要改 cocos2d-html5 去读 twE 字段,而 cocos2d-x 那边的 cpp 代码也要一起变动,代价有点大。所以我决定修改 DragonBones for cocos2d-x 插件,让它输出 tweenFrame 字段:

但由于上面的逻辑BUG,导致 Boolean("0")==true 只好连 cocos2d-html5 的源码一并修改,稍后再向官方提交一个issue

var isTween = frameXML.getAttribute(ccs.CONST_A_TWEEN_FRAME) || true;
frameData.isTween = (isTween != "0" && isTween != "false");

翻阅了一下 cpp 的代码,它是用 tinyxml 的 QueryBoolValue 来读 tweenFrame 字段,“0” 和 “false” 都能正确解析为 false

由于以前经常把玩 Flash,所以对 DragonBones for cocos2d-x 的插件修改较为顺利。在这里就不多说了,直接提供下载地址:

插件下载

https://github.com/mutoo/dragonbones-for-cocos2d-x/raw/master/build/DragonBonesDesignPanel.zxp

其它

若是要使 ^ 与 帧事件 @event_name 和 子骨骼动作 #mov_name 一起生效,可以用 | 将各个部分隔开,但 ^ 必须放在第一个,如 ^|#fire