dragonBones5.6.300解析关键帧的actions异常的bug

db5.6和db5.7的差异

我看到creator使用的龙骨是5.6(dragonebones/lib/dragonbones.js),我build了dragonBones官方的源码,发现creator 2.4.10使用的是自己修改过的,主要是删除了yDown的逻辑

修改的内容还是比较多的,但是去cocos仓库找到了对应的龙骨仓库,发现编译出来的还是和2.4.10内置的不一样,我只看到了修改过package.json,后来问了才知道是直接对build的结果上修改的。

没办法,只能参考ts源码,硬啃dragonBones.js的代码了

最小可复现demo

当第10帧增加一个关键帧,问题就消失了

所有的关键帧都是在切换动画

js 复制代码
Armature.prototype.advanceTime = function (passedTime) {
     // Do actions.要观察_actions的来源
    if (this._actions.length > 0) {
        this._lockUpdate = true;
        for (var _i = 0, _a = this._actions; _i < _a.length; _i++) {
            var action = _a[_i];
            var actionData = action.actionData;
            if (actionData !== null) {
                if (actionData.type === 0 /* Play */) {
                    if (action.slot !== null) {
                        var childArmature = action.slot.childArmature;
                        if (childArmature !== null) {
                            childArmature.animation.fadeIn(actionData.name);
                        }
                    }
                    else if (action.bone !== null) {
                        for (var _b = 0, _c = this.getSlots(); _b < _c.length; _b++) {
                            var slot = _c[_b];
                            if (slot.parent === action.bone) {
                                var childArmature = slot.childArmature;
                                if (childArmature !== null) {
                                    childArmature.animation.fadeIn(actionData.name);
                                }
                            }
                        }
                    }
                    else {
                        this._animation.fadeIn(actionData.name);
                    }
                }
            }
            action.returnToPool();
        }
        this._actions.length = 0;
        this._lockUpdate = false;
    }
    this._proxy.dbUpdate();
}

Armature.prototype._bufferAction = function (action, append) {
    if (this._actions.indexOf(action) < 0) {
        if (append) {
            this._actions.push(action);
        }
        else {
            this._actions.unshift(action);
        }
    }
};
js 复制代码
// 获取rawData[key]的值,如果不存在则返回defaultValue
ObjectDataParser._getNumber = function (rawData, key, defaultValue) {
    if (key in rawData) {
        var value = rawData[key];
        if (value === null || value === "NaN") {
            return defaultValue;
        }
        return +value || 0;
    }
    return defaultValue;
};

dragonBones的数据结构是非常紧凑的

  • frameArray
js 复制代码
// 对displayFrame的解析,2个一组,格式为 [frame_start, display-index]
0,0,  20,0,  // slot-pan
0,0,  10,0,  // slot-yupian
//-------------------分割线-----------------------
0,2, // [frame_start, action_count],因为有2个action,所以后边数2个
0,2, // 对应this._armature._actions里面的偏移,数据来自_mergeActionFrame的结果

20,1, // 与上同理
1,

0,-1,0,-1,0
  • timelineArray
js 复制代码
100, // scale,
0,   // offset
2,   // displayFrameCount
0,   // frameValueCount永远是0
0,   // animation.frameIntOffset、animation.frameFloatOffset、0
// 以上5个数值是配置数据,后边的数据长度和displayFrameCount有关系,这里是2
0, // frame1的frameArray偏移,对应的事slot-pan
2, // frame2的frameArray偏移

// 新的数据
100,0, 2 ,0,0,// 5个配置数据
4,6, // 对应的事slot-yupian
//-------------------分割线-----------------------
// 新数据
100,0, 3 ,0,0,
8,12,0,

// 新数据
100,0, 1 ,0,0,
0,

// 新数据
100,0, 1 ,0,0,
0
js 复制代码
ObjectDataParser.prototype._mergeActionFrame = function (rawData, frameStart, type, bone, slot) {
    var actionOffset = dragonBones.DragonBones.webAssembly ? this._armature.actions.size() : this._armature.actions.length;
    // 将当前displayFrame里面的actions序列话出来
    var actions = this._parseActionData(rawData, type, bone, slot);
    var frameIndex = 0;
    var frame = null;
    for (var _i = 0, actions_2 = actions; _i < actions_2.length; _i++) {
        var action = actions_2[_i];
        // 将每个action都放到armature里面
        this._armature.addAction(action, false);
    }
    if (this._actionFrames.length === 0) { // First frame.
        frame = new ActionFrame();
        frame.frameStart = 0;
        this._actionFrames.push(frame);
        frame = null;
    }
    // 找到起始帧相同的frame
    for (var _a = 0, _b = this._actionFrames; _a < _b.length; _a++) { // Get same frame.
        var eachFrame = _b[_a];
        if (eachFrame.frameStart === frameStart) {
            frame = eachFrame;
            break;
        }
        else if (eachFrame.frameStart > frameStart) {
            break;
        }
        frameIndex++;
    }
    if (frame === null) { // Create and cache frame.
        frame = new ActionFrame();
        frame.frameStart = frameStart;
        this._actionFrames.splice(frameIndex + 1, 0, frame);
    }
    // 将这个action放在对应frameStart的_actionsFrame里面
    // 这样在播放到某一帧的时候,我们就知道该帧都要触发哪些actions
    // 这里只是索引, 从this._armature.actions里面获取
    for (var i = 0; i < actions.length; ++i) { // Cache action offsets.
        frame.actions.push(actionOffset + i);
    }
};

从这个actionFrames里面我们可以推理出

  • 第00帧,播放[0-pan, 2-yu14]
  • 第10帧,播放3 yu15
  • 第20帧,播放1 pan

脑补一下效果也没啥问题,接着看解析

应该是这个this._actionFrames的问题,因为它是先把20送进去的导致了无法解析到10

我尝试着拍了下序列

javascript 复制代码
this._actionFrames.sort((a,b)=>{return a.frameStart-b.frameStart;});

这样解析到了,也正常了,牛逼~

修复方式

可以根据rawFrames的类型修复这个问题,但是这么干感觉风险比较大

另外的修复方式是在某个api之后,对this._actionFrames进行排序

可以看到解析原始json和frame都会经过_parseTimeline函数,他们都有一个公共的源头_parseAnimation,在解析完毕slot之后,再去解析frame的

所以我们可以对parseSlotTimelinehack,让其调用完毕后,对_actionFrames排序,观察下_parseSlotTimeline的函数原型,他是ObjectDataParser的成员函数

js 复制代码
ObjectDataParser.prototype._parseSlotTimeline = function (rawData) {

};

全局变量持有了这个对象dragonBones.ObjectDataParser,问题就变的很简单了

相关修复已经提交个cocos

最新的dragonBones似乎不是通过这种方式修复的

相关推荐
wuhen_n几秒前
破冰——建立我们的AI开发实验环境
前端·javascript
HelloReader4 分钟前
Flutter 自适应布局一套代码适配手机和平板(十二)
前端
牛奶7 分钟前
HTTP裸奔,HTTPS穿盔甲——它们有什么区别?
前端·http·https
梓言9 分钟前
tailwindcss构建执行npm exec tailwindcss init -p 报错
前端
哈罗哈皮10 分钟前
龙虾(openclaw)本地快速安装及使用教程
前端·aigc·ai编程
用户231154445305811 分钟前
React中实现“双向绑定”效果的几种方式
前端
HelloReader12 分钟前
Flutter Sliver 高级滚动打造 iOS 通讯录体验(十三)
前端
a11177644 分钟前
程序化几何背景生成器(html 开源)
前端·开源·html
浮笙若有梦1 小时前
我开源了一个比 Ant Design Table 更好用的高性能虚拟表格
前端·vue.js
一只程序熊1 小时前
vite-cool-unix-ctx] Unexpected token l in JSON at position 0
java·服务器·前端