跟随Colin学习,编写兼容Creator 1.x和2.x的代码!

作者: colinsusie 奎特尔星球 前天

前言

Creator 2.x出来有一段时间了,在原生应用上仍然不能让人满意,许多小伙伴花了大量精力把项目升级到2.x,结果发现性能内存大打折扣。

官方也意识这个问题,他们正组织核心人马,在对原生框架进行各种优化,包括Spine,Dragonbones,压缩纹理,文字优化等等,相信在不久的将来可以见到一些成效。

不过如果项目急着要上线,现在可能来不及了,并且优化的成果如何,也要实际放出来时测试过才能知道。在这种情况下,比较可行的方法是先用1.x发布你的应用,但在代码上作一些兼容性处理,确保到时升级时尽量平滑。甚至在最坏情况要回退,也少一些麻烦。

这篇文章试图将1.9和2.x的差异列举出来,并且告诉你如何写出在两个版本都可以运行的代码。1.10我们没有用过,使用1.10的小伙伴只能自行研究。

先定义版本常量

//如果是1.x的项目定义为true,如果是2.x的项目定义为false
window.CC_1X  = true

ZOrder的差异

1.9可以用node.setLocalZOrdernode.zIndex,2.x去掉了setLocalZOrder函数,要兼容的话统一使用node.zIndex

setCascadeOpacityEnabled废除

2.x去掉了node.setCascadeOpacityEnabled,1.9要兼容的话就不能使用。另外cc.Node上还有多个API被废除,详见Creator API文档,链接:https://docs.cocos.com/creator/api/zh/。

播放声音的差异

  • 1.9的例子:
let sId = cc.audioEngine.play(cc.url.raw("resources/sound/test.mp3")), loop, volume);
  • 2.x的例子:
cc.loader.loadRes("sound/test", cc.AudioClip, function (err, clip) {
    if (err) {console.error(err); return;}
    let sId = cc.audioEngine.play(clip, !!loop, volume);
});
  • 兼容的做法是写一个包装函数:
playSound = function (name, loop, volume=1, cb) {
    if (CC_1X) {
        let sId = cc.audioEngine.play(cc.url.raw("resources/sound/"+name+".mp3", !!loop, volume);
        if (cb) {
            cb(sId);
        }
    } else {
        cc.loader.loadRes("sound/"+name, cc.AudioClip, function (err, clip) {
            if (err) { console.error(err); return;}
            let sId = cc.audioEngine.play(clip, !!loop, volume);
            if (cb) {
                cb(sId);
            }
        });
    }
};

自定义事件的差异

  • 1.9的事件
// message 会被保存在回调函数的 event 参数的 detail 属性上
eventTarget.emit(type, message); 
eventTarget.on(type, function (event) {
    // 通过 event.detail 获取message
});
  • 2.x的事件
// emit 时可以传递至多五个额外参数,都会被扁平的直接传递给回调函数
eventTarget.emit(type, message, target); 
eventTarget.on(type, function (message, target) {
    // 直接通过回调参数来获取 emit 时传递的事件参数
});
  • 兼容的做法是确保参数只传一个,然后在事件处理是这样判断:
eventTarget.on(type, function (event) {
    let msg = event.detail ? event.detail : event;
    // 这样就能兼容1.9和2.x的事件机制
});
  • 由于自定义事件的变化,导致按钮,动画组件等事件也有相应的变化,兼容的做法如下:
// 按钮的
button.node.on("click", this.onClick, this);
onClick(event) {
    let button = event.detail ? event.detail : event;
}
// 动画的
anim.on("finished", this.onFinished, this);
onFinished(event, target) {
    var aniState = target ? target : event.target;
}

一些API的变化:

  • radiansToDegrees
if (CC_1X) {
    return cc.radiansToDegrees(dirRad);
} else {
    return cc.misc.radiansToDegrees(dirRad);
}
  • cc.KEY
if (CC_1X) {
    cc.macro.KEY = cc.KEY;
}
  • setKeepScreenOn
if (CC_1X) {
    cc.Device.setKeepScreenOn(true);
} else {
    jsb.Device.setKeepScreenOn(true);
}
  • 其他API不同,通过查询文档,然后用上面的方式写一个包装函数。

prefab的差异

我们当时将项目从2.0.5回退到1.9的时候,发现修改代码还不能成功,有些组件序列化格式的变化,导致用1.9打开会失败。

所以这里也将一些不兼容的地方列出来,方便有像我们一样想回退的小伙伴参考:

  • RichText:如果在2.0中设置了字符串,1.9打不开,解决办法是先在2.0编辑器中,将RichText的文本清空,1.9编辑器就可以正常打开了。

  • ScaleX和ScaleY属性如果不是1,回退到1.9会恢复成1。这也是因为格式不一致导致1.9没法解析出来。似乎没有好的办法,只能手动一个个修正过来。

  • EditBox 2.0多出几个子结点,要回到1.9只能手动删掉了,请看下图:

  • TTF字体:当字体文件体积大于10M时,2.0会加载失败,这应该属于引擎的BUG,期待后面修复。

meta文件的修改

  • .meta文件的版本号有变化,在2.x中有些是2.0.0的,如果想回退,可以用批处理替换回1.0.1。

其它差异

  • 2.x资源不存在直接报错,在运行时,1.x时资源不存在时只是做警告提示,2.x资源不存在直接报错。

  • 2.x构建资源全部以UUID命名:如果要在2.x上做热更新,需要建立Assets资源与构建资源的对应关系,相比1.x要复杂一些了。

  • rect.contains废弃使用cc.rectContainsPoint代替

  • cc.pXXX系列函数被废弃,使用cc.Vec2成员函数

    cc.pAdd需改为p.add,cc.pMult改为p.mul

两个点的距离计算cc.pDistance改为p1.sub(p2).mag()。


奎特尔星球

###「奎特尔星球」快突破900人了,在这里真诚邀请大家前来投稿,分享你的经验,在游戏开发的道路上我们一起结伴砥砺前行!

8赞

牛逼,先占个座

厉害了哥

好贴:+1:

这是踏了多少坑:joy:

mark

好贴,自己之前升级2.x版本也遇到了这些问题, 但是没有像这样总结出来,给楼主一个赞

感觉2.0.7原生占用内存太大了啊!游戏打开直接600M就挂了

这是游戏加载的资源多吧,一张2048*2048的png在内存中是16M