3.6 模拟器 2D 显示排序失效?

  • Creator 版本: 3.6.0

  • 目标平台: iOS / Android / 模拟器

  • 重现方式:多个2D显示对象,3.5版本使用node.children.sort排序后,显示对象的渲染顺序正常,在3.6.0版本中,web端正常,真机上就无效了.

  • 重现概率: 100%

具体代码发一下

这是在3.6.0版本下的测试代码.
正常情况下,3盖住2盖住1
在web端运行没有问题,cc里用模拟器运行,就无效了

assets.zip (118.4 KB)

这是模拟器上的效果:


这是在浏览器里运行的效果:

请问这个问题在修复中了吗?这个问题对于我的项目来说,非常非常重要…

3.6 中,Node 已经在原生上实现了。ts 的 children 和 c++ 的 children 需要同步操作。
理论上不应该直接在 ts 中拿 children 去做 sort 的操作,可能 Node 需要提供类似的 sortChildren 的API给开发使用会更合理点。

当前临时处理的话,可以尝试一下,在 this.node.children.sort 之后调用一下 this.node._setChildren 私有接口进行强行同步下 children 到 c++ 层中。

if (this.node._setChildren) {
    this.node._setChildren(this.node.children);
}

在2D的斜视角游戏里,对物体的显示排序是硬需求,希望下一个版本可以有更合理的api直接在ts里调用

1赞


没有此方法…

if ((this.node as any)._setChildren) {
            (this.node as any)._setChildren(this.node.children);
}

先是取消了对节点设置zIndex后自动排序
现在children也不给排序
你们干这些事情的时候,没有讨论一下的么
产品经理不参加review,不盯一下工作计划的么 @jare
感觉3.x以来,你们团队就变得乱糟糟,是人太多管理不过来了么

原生化之后,所有绑定对象的 Pure JS Array 和 Object 类型的属性,都不允许直接修改内部量,这是 JS 特性导致的无法做到的结果。

对于 Node 来说,属性是 children,它的类型是数组,要改变这个属性的内容,必须重新进行赋值,这样原生侧才有可能得到通知,如果直接修改 JS Array 本身,C++ 是不可能得到通知,也不知道这个属性的改变。除了 children 以外,position 不允许直接对分量进行修改 position.x = 0 也是一样的原因。

这些问题不可避免,我们也尝试过通过 Object.freeze API protect 属性,参考我这个 PR,但是由于 loose 模式下实际上不会得到任何通知,所以其实没有任何保护效果。而且 freeze 会带来额外的性能开销,所以放弃了。

原生化过程中,请注意,只能使用引擎公开 API,下面这类的用法都是错误的

node.children.splice(0, 1);
node.children.sort(callback);
node.position.x = 0;
component.color.r = 255;

可以参考文档 开发注意事项 · Cocos Creator

  • 定制引擎, 加上上面大佬说的代码(2d显示排序的老方法再坚持坚持 :joy:)
    private static _sortChildrenSibling (node) {
        const siblings = node.children;
        if (siblings) {
            siblings.sort((a:Node, b:Node) => {
                ...
            });
            // https://forum.cocos.org/t/topic/138996/6
            if ((node as any)._setChildren) {
                (node as any)._setChildren(siblings);
            }
        }
    }