Prefab极简解析库

有时候,我们需要对cocos的预制体做简单处理,比如获取prefab包围盒大小,或者改改其中几个值,又不想用插件方式去实现,毕竟还是功能简单,插件方式又太麻烦;
那我们就自己解析下prefab,毕竟只是一个json,这里就提供一个node环境下简单的prefab解析工具,只读取了其中几个值,大家可以自行扩展:

class Prefab {
    constructor(jsonData) {
        this.jsonData = jsonData;
        this._elements = [];

        this.parseJson();
    }

    get name() {
        return this.jsonData._name;
    }

    parseJson() {
        this.jsonData.forEach((element) => {
            let elm = null;
            switch(element.__type__) {
                case "cc.Node":
                    elm = new Node(this, element);
                    break;
                case "cc.UITransform":
                    elm = new UIComponent(this, element);
                    break;
                case "cc.Sprite":
                    elm = new Sprite(this, element);
                    break;
                default:
                    elm = new Component(this, element);
                    break;
            }
            this._elements.push(elm);
        }); 

        this._elements.forEach((element) => {
            element.parseJson();
        });
    }

    getElement(id) {
        return this._elements[id];
    }

    getNode(name) {
        for(let i = 0; i < this._elements.length; i++) {
            let element = this._elements[i];
            if(element.name == name && element.type == "cc.Node") {
                return element;
            }
        }
        return null;
    }

    findNode(name) {
        let split = name.split("/");
        let node = null;
        for(let i = 0; i < split.length; i++) {
            if(i == 0) {
                node = this.getNode(split[i]);
            }else{
                node = node.getNode(split[i]);
            }
            if(!node) {
                return null;
            }
        }
        return node;
    }
}

class Element {
    constructor(prefab, jsonData) {
        this.prefab = prefab;
        this.jsonData = jsonData;
    }

    get type() {
        return this.jsonData.__type__;
    }

    get name() {
        return this.jsonData._name;
    }

    parseJson() {
        
    }
}

class Node extends Element {
    constructor(prefab, jsonData) {
        super(prefab, jsonData);

        this._children = [];
        this._components = [];
        this._uiComponent = null;
    }

    get children() {
        return this._children;
    }

    get components() {
        return this._components;
    }

    get uiComponent() {
        return this._uiComponent;
    }

    get pos() {
        return this.jsonData._lpos;
    }

    get scale() {
        return this.jsonData._lscale;
    }

    getChild(name) {
        for(let i = 0; i < this._children.length; i++) {
            let child = this._children[i];
            if(child.name == name) {
                return child;
            }
        }
        return null;
    }

    findChild(name) {
        let split = name.split("/");
        let child = null;
        for(let i = 0; i < split.length; i++) {
            child = child.getChild(split[i]);
            if(!child) {
                return null;
            }
        }
        return child;
    }

    getComponent(type) {
        for(let i = 0; i < this._components.length; i++) {
            let component = this._components[i];
            if(component.type == type) {
                return component;
            }
        }
        return null;
    }

    parseJson() {
        for(let i = 0; i < this.jsonData._children.length; i++) {
            let child = this.jsonData._children[i];
            let id = child.__id__;
            this._children.push(this.prefab.getElement(id));
        }

        for(let i = 0; i < this.jsonData._components.length; i++) {
            let component = this.jsonData._components[i];
            let id = component.__id__;
            let comp = this.prefab.getElement(id);
            this._components.push(comp);

            if(!this._uiComponent && comp.type == "cc.UITransform") {
                this._uiComponent = comp;
            }
        }
    }
}

class Component extends Element {
    constructor(prefab, jsonData) {
        super(prefab, jsonData);
    }

    parseJson() {
        
    }
}

class UIComponent extends Component{
    parseJson() {
        
    }

    get anchorPoint() {
        return this.jsonData._anchorPoint;
    }

    get contentSize() {
        return this.jsonData._contentSize;    
    }
}

class Sprite extends Component{
    parseJson() {
        
    }
}

module.exports = {
    Prefab,
    Node,
    Component,
    UIComponent,
    Sprite,
}
5赞

:partying_face: :partying_face: :partying_face:

如果是我会选择 copy 引擎代码,就不用自己写了

说的对,不过不看复杂度的么

最近整想着这种类似的东西。之前那个讨论编辑器中拖拽方式绑定对象或者点击事件导致代码中查看困难的问题,对于已有项目,可以通过整一个预制体解析的工具来辅助一下。

可以的,之前想过,感觉工作量大(懒),就没做

有办法让一个节点直接用代码生成预制体吗?

理论上是可以的,不过需要考虑的东西多,这个还不如用插件方式

哈哈,这个脚本可以做些奇奇怪怪的操作

:wink:是的呀

mark~~~

需求不一样,我想做的是, 快速生成prefab, 然后快速让这个prefab添加到场景(不是游戏运行的, 是编辑器状态的), 现在几个难点都没解决, 首先是如何快速用代码生成prefab? 如何让我的插件窗口显示这个prefab的缩略图(现在什么预制体都看起来一样,找起来也麻烦)

嗯。我也有这个想法,我有需求把现有预制体改造成一个独立的包,需要那个下哪个,避免文件过多,但是还没想好方法