Creator3D: executeInEditMode下创建的Node预览错误

问题描述:

  1. executeInEditMode下创建的Node,在预览窗口中选中后不显示包围盒和坐标箭头
  2. executeInEditMode下移除的Node,在预览窗口中依然残留

错误演示视频:
https://v.qq.com/x/page/l30081e78gf.html

可重现的脚本:

import { _decorator, Component, Node, Prefab, instantiate, v3 } from "cc";
const { ccclass, property, executeInEditMode } = _decorator;

@ccclass("EditorCreate")
@executeInEditMode
export class EditorCreate extends Component {

    @property(Prefab)
    model: Prefab = null;

    onEnable() {
        this.node.removeAllChildren();

        if (this.model) {
            for (let i = 0; i < 10; ++i) {
                let box: Node = instantiate(this.model);
                this.node.addChild(box);
                box.position = v3(i * 1.1, 0, i * 1.1);
            }
        }
    }

    onDisable() {
        this.node.removeAllChildren();
    }

}

另 console.log 和 cc.log 似乎不再会出现在编辑器的Console中呀,跟2.x不太一样

console 是因为 3d 场景里 log 多了很多,如果都打印出来,编辑器的 log 会有一大堆。所以现在只输出了 warn 及以上的消息。warn error 之类的。

executeInEditMode 问题我们修复下,谢谢反馈啦。

目前编辑器扩展结构还不完善,会在1.1中有比较好的支持,目前可以通过以下比较麻烦的代码支持:

import { _decorator, Component, Node, Prefab, instantiate, v3 } from "cc";
import { changeExt } from "upath";
const { ccclass, property, executeInEditMode } = _decorator;

declare const cce: any;

@ccclass("EditorCreate")
@executeInEditMode
export class EditorCreate extends Component {

    @property(Prefab)
    model: Prefab = null;

    onEnable() {
        if (CC_EDITOR) {    // 只在编辑器环境下执行
            this.node.removeAllChildren();

            if (this.model) {
                for (let i = 0; i < 10; ++i) {
                    let box: Node = instantiate(this.model);
                    cce.Node.add(box);  // 加入到Node管理器中
                    cce.Node.emit('add', box);  // 发送添加消息
                    cce.Ipc.forceSend('broadcast', 'scene:add-node', box.uuid); // 广播添加节点消息
                    this.node.addChild(box);
                    cce.Node.emit('change', this.node); // 发送父节点改变消息
                    box.position = v3(i * 1.1, 0, i * 1.1);
                }
            }
        }
    }

    onDisable() {
        this.node.removeAllChildren();
    }

}

感谢,同问,removeChild后 预览中残留,有什么办法呢?

似乎是有BUG,如果着急用的话,试一下这个PR:
https://github.com/cocos-creator/engine/pull/5547/commits/e8c3b2ce09aa5ffd022ef800e167585b31b47547

这两处代码都是有问题的,在 onEnable 和 onDisable 阶段是绝对不能更改当前正在 enable / disable 的节点树的。我会添加一个警告来保护。

为什么你想要移除节点呢?具体你的功能的需求是什么?

这个脚本是为了在编辑器中,自动生成一些Node。(仅运行在编辑器中)
每次需要重新生成时,就是将这个组件取消勾选,再打开勾选。

其实有个建议哈~~~
是否能在组件中,就增加一个编辑器面板上的按钮呢?~ 例如

export class XXX extends Component {

  @editorButton('生成节点')
  generateNodes(){
     // removeAllChildren && addChild ...
  }

}

这个功能用基础的属性就能做的,例如

@property    
public get doSomeThing () {
   return false; // bool 类型
}

public set doSomeThing (v) {
    if (CC_EDITOR) {
       /** TODO */
    }
}     

嗯,推荐向上面说的一样用简单的函数来实现功能,不要放在 onEnable / onDisable 中,下个版本会做更严格校验,如果在 Activate、Desactivate 阶段修改子节点就会报错。

你要的 inspector 定制功能其实是有的,自己可以写 html 作为 inspector 布局的来源,但是目前还没有文档化这些接口