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似乎不是通过这种方式修复的

相关推荐
明辉光焱2 分钟前
[Electron]总结:如何创建Electron+Element Plus的项目
前端·javascript·electron
牧码岛22 分钟前
Web前端之汉字排序、sort与localeCompare的介绍、编码顺序与字典顺序的区别
前端·javascript·web·web前端
开心工作室_kaic38 分钟前
ssm111基于MVC的舞蹈网站的设计与实现+vue(论文+源码)_kaic
前端·vue.js·mvc
晨曦_子画1 小时前
用于在 .NET 中构建 Web API 的 FastEndpoints 入门
前端·.net
慧都小妮子1 小时前
Spire.PDF for .NET【页面设置】演示:在 PDF 文件中添加图像作为页面背景
前端·pdf·.net·spire.pdf
咔咔库奇1 小时前
ES6基础
前端·javascript·es6
Jiaberrr1 小时前
开启鸿蒙开发之旅:交互——点击事件
前端·华为·交互·harmonyos·鸿蒙
徐小夕1 小时前
Flowmix/Docx 多模态文档编辑器:V1.3.5版本,全面升级
前端·javascript·架构
Json____1 小时前
学法减分交管12123模拟练习小程序源码前端和后端和搭建教程
前端·后端·学习·小程序·uni-app·学法减分·驾考题库