龙骨动画在iOS上报错

我使用的环境如下:
creator2.0.9p1
xcode10.1
mac10.14

首先,报错的龙骨动画在win7上的creator2.0.9p1构建到微信平台时是没有问题的。
至于在iOS出错的原因,经过我的排查,是因为引擎在构建到微信平台和构建到iOS平台时调用的源代码不同,前者
用的是js,后者用的是c++。

(1)报错误:Same slot
js中:
C:/CocosCreator2.0.9p1/resources/engine/extensions/dragonbones/lib/dragonBones.js----------
ArmatureData.prototype.addSlot = function (value) {
if (value.name in this.slots) {
console.warn("Same slot: " + value.name);
return;
}
this.slots[value.name] = value;
this.sortedSlots.push(value);
};

c++中:
cocos/Contents/resources/cocos2d-x/cocos/editor-support/dragonbones/model/ArmatureData.cpp----------
void ArmatureData::addSlot(SlotData* value)
{
if (slots.find(value->name) != slots.cend())
{
DRAGONBONES_ASSERT(false, "Same slot: " + value->name);
return;
}
slots[value->name] = value;
sortedSlots.push_back(value);
}

很容易可以看出这2段代码差别在哪里,就是构建到iOS平台时调用的源代码用到了一个断言。
好吧,这个错误很容易改。我直接打开龙骨动画的编辑器,将重复名字的slot重名字,然后重新导出就可以了。
但事情往往没那么简单,我又遇到了第2个报错。

(2)报错误:DragonBones::JSONDataParser index is invalid
js中:
C:/CocosCreator2.0.9p1/resources/engine/extensions/dragonbones/lib/dragonBones.js----------
ObjectDataParser.prototype._parseZOrderFrame = function (rawData, frameStart, frameCount) {
var frameOffset = this._parseFrame(rawData, frameStart, frameCount);
if (dragonBones.DataParser.Z_ORDER in rawData) {
var rawZOrder = rawData[dragonBones.DataParser.Z_ORDER];
if (rawZOrder.length > 0) {
var slotCount = this._armature.sortedSlots.length;
var unchanged = new Array(slotCount - rawZOrder.length / 2);
var zOrders = new Array(slotCount);
for (var i_1 = 0; i_1 < unchanged.length; ++i_1) {
unchanged[i_1] = 0;
}
for (var i_2 = 0; i_2 < slotCount; ++i_2) {
zOrders[i_2] = -1;
}
var originalIndex = 0;
var unchangedIndex = 0;
for (var i_3 = 0, l = rawZOrder.length; i_3 < l; i_3 += 2) {
var slotIndex = rawZOrder[i_3];
var zOrderOffset = rawZOrder[i_3 + 1];
while (originalIndex !== slotIndex) {
unchanged[unchangedIndex++] = originalIndex++;
}
var index = originalIndex + zOrderOffset;
zOrders[index] = originalIndex++;
}
while (originalIndex < slotCount) {
unchanged[unchangedIndex++] = originalIndex++;
}
this._frameArray.length += 1 + slotCount;
this._frameArray[frameOffset + 1] = slotCount;
var i = slotCount;
while (i–) {
if (zOrders[i] === -1) {
this._frameArray[frameOffset + 2 + i] = unchanged[–unchangedIndex] || 0;
}
else {
this._frameArray[frameOffset + 2 + i] = zOrders[i] || 0;
}
}
return frameOffset;
}
}
this._frameArray.length += 1;
this._frameArray[frameOffset + 1] = 0;
return frameOffset;
};

c++中:
cocos/Contents/resources/cocos2d-x/cocos/editor-support/dragonbones/parser/JSONDataParser.cpp-----------
unsigned JSONDataParser::_parseZOrderFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount)
{
const auto frameOffset = _parseFrame(rawData, frameStart, frameCount);

if (rawData.HasMember(Z_ORDER))
{
    const auto& rawZOrder = rawData[Z_ORDER];
    if (!rawZOrder.Empty()) 
    {
        const auto slotCount = _armature->sortedSlots.size();
        std::vector<int> unchanged;
        std::vector<int> zOrders;
        unchanged.resize(slotCount - rawZOrder.Size() / 2);
        zOrders.resize(slotCount);

        for (std::size_t i = 0; i < unchanged.size(); ++i)
        {
            unchanged[i] = 0;
        }

        for (std::size_t i = 0; i < slotCount; ++i) 
        {
            zOrders[i] = -1;
        }

        unsigned originalIndex = 0;
        unsigned unchangedIndex = 0;
        for (std::size_t i = 0, l = rawZOrder.Size(); i < l; i += 2) 
        {
            const auto slotIndex = rawZOrder[i].GetInt();
            const auto zOrderOffset = rawZOrder[i + 1].GetInt();
            while (originalIndex != (unsigned)slotIndex)
            {
                unchanged[unchangedIndex++] = originalIndex++;
            }
            
            unsigned index = originalIndex + zOrderOffset;
            CCASSERT(index >= 0 && index < zOrders.size(), "DragonBones::JSONDataParser index is invalid");
            zOrders[index] = originalIndex++;
        }

        while (originalIndex < slotCount) 
        {
            unchanged[unchangedIndex++] = originalIndex++;
        }

        _frameArray.resize(_frameArray.size() + 1 + slotCount);
        _frameArray[frameOffset + 1] = slotCount;

        int i = slotCount;
        while (i--) 
        {
            if (zOrders[i] == -1) 
            {
                _frameArray[frameOffset + 2 + i] = unchanged[--unchangedIndex];
            }
            else {
                _frameArray[frameOffset + 2 + i] = zOrders[i];
            }
        }

        return frameOffset;
    }
}

_frameArray.resize(_frameArray.size() + 1);
_frameArray[frameOffset + 1] = 0;

return frameOffset;

}

请注意2段代码中第3个for中的内容,构建到iOS平台时调用的源代码用到了一个断言,如下
CCASSERT(index >= 0 && index < zOrders.size(), “DragonBones::JSONDataParser index is invalid”);

而构建到微信平台调用的源代码则没有这个判断,因为js允许zOrders[-1]这样的写法,只不过负数被当做数组的对象属性的名称了,
且不算在zOrders.length中。

另外,还有一处差别,
js中:
this._frameArray[frameOffset + 2 + i] = unchanged[–unchangedIndex] || 0;
c++中:
_frameArray[frameOffset + 2 + i] = unchanged[–unchangedIndex];

以上也可以看出,js代码的容错性真是高,unchanged[–unchangedIndex] || 0 保证了在unchangedIndex为负数时也可以使用默认值0。
c++就做不到了,妥妥地越界报错啊。只不过,cocos官方在c++这里没有做保底判断,也真是有点偷懒了啊。因为,我这边出错的这个龙骨
动画既然导出时没有问题,偏偏放到iOS上出问题,这该找谁去解决啊。难道让美术重做动画?这显然是不可行的。只能我这个程序去解决
问题了。我只能说这太坑了。

我这里权益的解决方法是仿照js的代码去修改c++的代码,如下:

CCASSERT(index >= 0 && index < zOrders.size(), “DragonBones::JSONDataParser index is invalid”);
替换为
if(!(index >= 0 && index < zOrders.size())){
originalIndex++;
continue;
}


_frameArray[frameOffset + 2 + i] = unchanged[–unchangedIndex];
替换为
if(unchangedIndex > 0){
_frameArray[frameOffset + 2 + i] = unchanged[–unchangedIndex];
}else{
_frameArray[frameOffset + 2 + i] = 0;
}

替换后,在xcode上重新编译,龙骨动画是可以播放了,只不过还是有点小瑕疵,但还在可承受的范围内。
至此,希望引擎组的大佬们能继续完善creator。
我的demo(win7上的,要想在iOS上测试,请在mac上新建一个项目,将demo的assets拷贝过来即可,另外,会
出错动画是503,运行后点击“下一个boss”切换即可):
testDragonBone1.rar (727.9 KB)

2赞

遇到同样问题,尝试解决中。。

同样遇到这个问题,问题与(2)报错,以及debug行数一模一样

遇到相同问题 ,按你的方式解决了。
感谢~

这个问题从升2.0之后就一直有。升2.0.7版本时这样,2.2.1了,还是这样。引擎组可否合并一下?从目前我的实际使用过程来讲,这样改没有造成崩溃什么之类的衍生问题。每次升版本都要重新改一遍引擎代码太蛋疼。 @jare

ver2.2.2 win10

我擦。。。我今天也遇到这个了。。在龙骨软件里啥事没有。。导入游戏里就报这个错,我的是在模拟器里报的错
10多个动画,就一个动画有这个错误。。
负责龙骨的同学。。看到的话麻烦回一下。。
真不愿意定制引擎,上次定制的我都有阴影了

遇到相同问题,但是没有修改源码,而是修改动画。出现这个问题的动画在万千之中只有一个。

这个动画中绘制顺序属性 就是导出的zOrder,若是导出有负数,那必然重触发上述断言闪退。比如

在pc上完整调试,如图

根据龙骨动画官方数据说明,如图:


也就说上面我提到的zOrder=[0, -1]是合法的,是可以取到-1的,那么这样的话,cocos引擎中的断言处理是不妥的,可以说是bug。当zOrder为[0, -1], 即这个长度为2时,就百分百触发断言。

mark!

遇到十个龙骨中有一个一直报错的再模拟器上Expression:index >= 0 && index < zOrders.size。最后发现是美术再做龙骨和psd图层有修改所以报错,不知道跟你们的是否一样问题

能说下具体问题吗 我们原话找不到问题 一直闪退

不知道你们怎么解决的,我是把
DRAGONBONES_ASSERT( false , "Same slot: " + value->name);
这句代码注释掉了,然后运行就没有问题了,哈哈,希望有人跟我指出这样有什么风险,然后告诉我正确的解决办法

感谢宝贵意见. 已经在3.0版本和2.4.5进行了优化

请问使用的什么版本

使用的是2.3.3版本

新版本会修复. 可以先按上面方法改