我使用的环境如下:
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)