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的
所以我们可以对parseSlotTimeline
hack,让其调用完毕后,对_actionFrames排序,观察下_parseSlotTimeline
的函数原型,他是ObjectDataParser的成员函数
js
ObjectDataParser.prototype._parseSlotTimeline = function (rawData) {
};
全局变量持有了这个对象dragonBones.ObjectDataParser
,问题就变的很简单了
相关修复已经提交个cocos
最新的dragonBones似乎不是通过这种方式修复的