目录

1.工具制作的起因

2.工具的制作

(1).首先在Assets->Editor 目录下创建脚本

(2).创建一个工具窗口

(3).在OnGUI()中draw出来一些按钮/label 等

(4).查询方法

(5).替换方法

3.效果展示:

4.拓展:

5.完整代码:


1.工具制作的起因

现在大多数公司做游戏为了压缩时间和成本,基本都会直接拿以前或者是直接从网上找一些开源的游戏代码,在此基础上进行二次创作,在这种代码环境下做一些新的逻辑,难免会遇到一些困难,比如:

我在开发过程中需要加一个新的layer层来完成我的新代码逻辑 ,但是发现旧的代码已经把全部的layer用掉了我们都知道layer层是没办法添加的。
不明白为什么不能添加的同学可以看下:

Unity layer的介绍与使用以及只有32层的原因

因此我就只能写一个查找预制体layer的工具 以此来找到使用次数最少的layer层,以此来减轻更改layer层对原逻辑的影响。

2.工具的制作

(1).首先在Assets->Editor 目录下创建脚本

(2).创建一个工具窗口

代码如下:

public class ReadOrWriteLayer : EditorWindow{
 static string checkPath;
 [MenuItem("SelfTools / 打开layer查找窗口")]
 public static void OpenWindow() {
         ReadOrWriteLayer readOrWriteLayer = EditorWindow.GetWindow<ReadOrWriteLayer>();
         readOrWriteLayer.Show();
         checkPath = "Assets";
     }
 }

其中 :ReadOrWriteLayer 是创建类名
            checkPath 是查找的路径
注意:我们的类要继承EditorWindow

(3).在OnGUI()中draw出来一些按钮/label 等
 

代码如下: 

 

GUILayout.BeginHorizontal();
         checkPath = EditorGUILayout.TextField("输入当前查找/替换的路径:", checkPath);
         GUILayout.EndHorizontal();
         GUILayout.Space(10);

动态修改checkPath 即 修改查找或者替换的路径 

GUILayout.BeginHorizontal();
         chechLayer = EditorGUILayout.TextField("输入当前查找的layer层:", chechLayer);
         GUILayout.EndHorizontal();
         GUILayout.Space(10);        GUILayout.BeginHorizontal();
         replaceLayer = EditorGUILayout.TextField("输入替换的layer层:", replaceLayer);
         GUILayout.EndHorizontal();
         GUILayout.Space(10);



分别输入要查找的layer层和要替换的layer层其中 chechLayer是要查找的layer层 replaceLayer是要替换成的layer层 

GUILayout.BeginHorizontal();
         if(GUILayout.Button("开始查找", "buttonleft", GUILayout.Width(250),            GUILayout.Height(50))) {
             if(!int.TryParse(chechLayer, out layer)) {
                 chechLayer = "";
             } else
                 CheckAllGameObjectByLayer();
         }GUILayout.EndHorizontal();
 GUILayout.Space(10);

添加按钮
点击后执行查找方法 CheckAllGameObjectByLayer(); 检查输出所有查询的layer预制体路径和子节点路径

GUILayout.BeginHorizontal();
         if(GUILayout.Button("开始替换", "buttonleft", GUILayout.Width(250), GUILayout.Height(50))) {
             if(!int.TryParse(chechLayer, out layer) || !int.TryParse(replaceLayer, out replacelayer)) {
                 chechLayer = "";
             } else
                 ReplaceAllGameObjectLayer();
         }
         GUILayout.EndHorizontal();
         GUILayout.Space(10);

添加按钮
点击后执行查找方法 ReplaceAllGameObjectLayer(); 替换所有查询的layer层为替换layer层

(4).查询方法

private void CheckAllGameObjectByLayer() {
    //写入进度条的当前值
        startVal = 0f;
        //输出文件保存路径
        savePath = Application.dataPath + "/Editor/LayerSetting.text";
        if(File.Exists(savePath))
            File.Delete(savePath);
        string allStr = "";
        //查找checkPath路径下的所有文件路径
        string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
        maxValue = allPath.Length;
        if(allPath.Length > 0) CreateFile();
        //把预制体和预制体里面的子物体写入到文件LayerSetting.text中
        using(FileStream fs = new FileStream(savePath, FileMode.Open)) {
            StreamWriter sw = new StreamWriter(new BufferedStream(fs), Encoding.UTF8);
            for(int i = 0; i < allPath.Length; i++) {
                if(File.Exists(allPath[i])) {
                    //通过路径获取游戏obj
                    GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
 		      if (obj == null) continue;
                    if(obj.layer == layer) {
                        allStr += string.Format("{0}\r\n", allPath[i]);
                        IterationAllGameObject(obj.transform, obj.name, ref allStr);
                        allStr += "\r\n";
                    } else {
                        IterationAllGameObject(obj.transform, obj.name, ref allStr);
                    }
                }
                startVal = i + 1;
                //刷新当前读取进度
                float slider = (float)startVal / maxValue;
                //参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
                EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
                //写入文件
                sw.Write(allStr);
                allStr = "";
            }
            sw.Close();
            fs.Close();
            fs.Dispose();
        }
        //全部结束关闭进度条
        EditorUtility.ClearProgressBar();
    }

   //如果保存文件不存在 创建一个
   private static void CreateFile() {
        if(!File.Exists(savePath)) {
            FileStream file = new FileStream(savePath, FileMode.Create);
            file.Dispose();
        }
    }

    //迭代obj的所有子物体
     private static void IterationAllGameObject(Transform obj, string path, ref string allStr, bool       writeLayer = false) {
        for(int i = 0; i < obj.childCount; i++) {
            GameObject child = obj.GetChild(i).gameObject;
            string realPath = path;
            if(!writeLayer) {
                if(child.layer == layer) {
                    realPath += string.Format("->{0}\r\n", child.name);
                    allStr += realPath;
                }
            } else {
                realPath += string.Format("->{0}    ::Layer -> {1}\r\n", child.name, child.layer);
                allStr += realPath;
            }

            string namePath = string.Format("{0} ->{1}", path, child.name);
            IterationAllGameObject(obj.GetChild(i), namePath, ref allStr, writeLayer);
        }
    }

(5).替换方法

private void ReplaceAllGameObjectLayer(bool checkLayer = true) {
        startVal = 0f;
        string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
        maxValue = allPath.Length;
        for(int i = 0; i < allPath.Length; i++) {
            if(File.Exists(allPath[i])) {
                GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
	         if (obj == null) continue;
                if(obj.layer == layer) {
                    obj.layer = replacelayer;
                } else if(!checkLayer) {
                    obj.layer = replacelayer;
                }
                IterationReplace(obj.transform, checkLayer);
            }
            startVal = i + 1;
            float slider = (float)startVal / maxValue;
            //参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
            EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
        }
        EditorUtility.ClearProgressBar();
        //保存全部修改
        AssetDatabase.SaveAssets();
    }

    private static void IterationReplace(Transform obj, bool checkLayer = true) {
        for(int i = 0; i < obj.childCount; i++) {
            GameObject child = obj.GetChild(i).gameObject;
            if(child.layer == layer) {
                child.layer = replacelayer;
            } else if(!checkLayer)
                child.layer = replacelayer;

            IterationReplace(obj.GetChild(i), checkLayer);
        }
    }

至此一个完整的layer层查询/替换工具诞生了

3.效果展示:

unity editor打开的预制体 unity预制体怎么修改_unity

unity editor打开的预制体 unity预制体怎么修改_游戏引擎_02

unity editor打开的预制体 unity预制体怎么修改_unity editor打开的预制体_03

unity editor打开的预制体 unity预制体怎么修改_FileStream_04

unity editor打开的预制体 unity预制体怎么修改_FileStream_05

unity editor打开的预制体 unity预制体怎么修改_unity_06

这个文件里就是查询的layer层的所有预制体的路径信息

点击替换 输入替换layer层就可以把文件中的所有预制体都替换掉

4.拓展:

由于每次都要手动填写查询目录 我觉得十分烦 想到unity有一个选中逻辑 于是添加了一条鼠标选中后路径更新
代码如下:

static bool isRun = false;
     bool toggle;    GUILayout.BeginHorizontal();
         toggle = EditorGUILayout.BeginToggleGroup("选择路径", toggle);
         if(Selection.assetGUIDs.Length > 0 && !isRun && toggle) {
             string selectPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
             checkPath = selectPath;
         }
         EditorGUILayout.EndToggleGroup();
         GUILayout.EndHorizontal();
         GUILayout.Space(10);

另外在替换或者查询中关闭isRun
效果如下:

unity editor打开的预制体 unity预制体怎么修改_unity_07

勾选选择路径之后 查找/替换路径会自动更换成鼠标选择的路径
注:鼠标选择之后需要移到此面板 此面板才会动态更新路径

5.完整代码:

using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;

public class ReadOrWriteLayer : EditorWindow {
    static string checkPath;
    static string savePath;

    string chechLayer;
    string replaceLayer;

    static int layer;
    static int replacelayer;

    float startVal;
    float maxValue;

    bool toggle;
    static bool isRun = false;

    [MenuItem("SelfTools / 打开layer查找窗口")]
    public static void OpenWindow() {
        ReadOrWriteLayer readOrWriteLayer = EditorWindow.GetWindow<ReadOrWriteLayer>();
        readOrWriteLayer.Show();
        checkPath = "Assets";
    }
    void  OnGUI() {

        GUILayout.BeginHorizontal();
        toggle = EditorGUILayout.BeginToggleGroup("选择路径", toggle);
        if (Selection.assetGUIDs.Length > 0 && !isRun && toggle)
        {
            string selectPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
            checkPath = selectPath;
        }
        EditorGUILayout.EndToggleGroup();
        GUILayout.EndHorizontal();
        GUILayout.Space(10);

        GUILayout.BeginHorizontal();
        checkPath = EditorGUILayout.TextField("输入当前查找/替换的路径:", checkPath);
        GUILayout.EndHorizontal();
        GUILayout.Space(10);

        GUILayout.BeginHorizontal();
        chechLayer = EditorGUILayout.TextField("输入当前查找的layer层:", chechLayer);
        GUILayout.EndHorizontal();
        GUILayout.Space(10);

        GUILayout.BeginHorizontal();
        replaceLayer = EditorGUILayout.TextField("输入替换的layer层:", replaceLayer);
        GUILayout.EndHorizontal();
        GUILayout.Space(10);

        GUILayout.BeginHorizontal();
        if(GUILayout.Button("开始查找", "buttonleft", GUILayout.Width(250), GUILayout.Height(50))) {
            if(!int.TryParse(chechLayer, out layer)) {
                chechLayer = "";
            } else
                CheckAllGameObjectByLayer();
        }
        GUILayout.EndHorizontal();
        GUILayout.Space(10);

        GUILayout.BeginHorizontal();
        if(GUILayout.Button("开始替换", "buttonleft", GUILayout.Width(250), GUILayout.Height(50))) {
            if(!int.TryParse(chechLayer, out layer) || !int.TryParse(replaceLayer, out replacelayer)) {
                chechLayer = "";
            } else
                ReplaceAllGameObjectLayer();
        }
        GUILayout.EndHorizontal();
        GUILayout.Space(10);
    }


    private void CheckAllGameObjectByLayer() {
        isRun = true;
        //写入进度条的当前值
        startVal = 0f;
        //输出文件保存路径
        savePath = Application.dataPath + "/Editor/LayerSetting.text";
        if(File.Exists(savePath))
            File.Delete(savePath);
        string allStr = "";
        //查找checkPath路径下的所有文件路径
        string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
        maxValue = allPath.Length;
        if(allPath.Length > 0) CreateFile();
        //把预制体和预制体里面的子物体写入到文件LayerSetting.text中
        using(FileStream fs = new FileStream(savePath, FileMode.Open)) {
            StreamWriter sw = new StreamWriter(new BufferedStream(fs), Encoding.UTF8);
            for(int i = 0; i < allPath.Length; i++) {
                if(File.Exists(allPath[i])) {
                    //通过路径获取游戏obj
                    GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
                    if (obj == null) continue;
                    if(obj.layer == layer) {
                        allStr += string.Format("{0}\r\n", allPath[i]);
                        IterationAllGameObject(obj.transform, obj.name, ref allStr);
                        allStr += "\r\n";
                    } else {
                        IterationAllGameObject(obj.transform, obj.name, ref allStr);
                    }
                }
                startVal = i + 1;
                //刷新当前读取进度
                float slider = (float)startVal / maxValue;
                //参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
                EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
                //写入文件
                sw.Write(allStr);
                allStr = "";
            }
            sw.Close();
            fs.Close();
            fs.Dispose();
        }
        //全部结束关闭进度条
        EditorUtility.ClearProgressBar();
        isRun = false;
    }

    //如果保存文件不存在 创建一个
    private static void CreateFile() {
        if(!File.Exists(savePath)) {
            FileStream file = new FileStream(savePath, FileMode.Create);
            file.Dispose();
        }
    }

    //迭代obj的所有子物体
    private static void IterationAllGameObject(Transform obj, string path, ref string allStr, bool writeLayer = false) {
        for(int i = 0; i < obj.childCount; i++) {
            GameObject child = obj.GetChild(i).gameObject;
            string realPath = path;
            if(!writeLayer) {
                if(child.layer == layer) {
                    realPath += string.Format("->{0}\r\n", child.name);
                    allStr += realPath;
                }
            } else {
                realPath += string.Format("->{0}    ::Layer -> {1}\r\n", child.name, child.layer);
                allStr += realPath;
            }

            string namePath = string.Format("{0} ->{1}", path, child.name);
            IterationAllGameObject(obj.GetChild(i), namePath, ref allStr, writeLayer);
        }
    }

    private void ReplaceAllGameObjectLayer(bool checkLayer = true) {
        isRun = true;
        startVal = 0f;
        string[] allPath = Directory.GetFiles(checkPath, "*.prefab", SearchOption.AllDirectories);
        maxValue = allPath.Length;
        for(int i = 0; i < allPath.Length; i++) {
            if(File.Exists(allPath[i])) {
                GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(allPath[i]);
                if (obj == null) continue;
                if (obj.layer == layer) {
                    obj.layer = replacelayer;
                } else if(!checkLayer) {
                    obj.layer = replacelayer;
                }
                IterationReplace(obj.transform, checkLayer);
            }
            startVal = i + 1;
            float slider = (float)startVal / maxValue;
            //参数1 为标题,参数2为提示,参数3为 进度百分比 0~1 之间
            EditorUtility.DisplayProgressBar("Loading", "写入中......", slider);
        }
        EditorUtility.ClearProgressBar();
        //保存全部修改
        AssetDatabase.SaveAssets();

        isRun = false;
    }

    private static void IterationReplace(Transform obj, bool checkLayer = true) {
        for(int i = 0; i < obj.childCount; i++) {
            GameObject child = obj.GetChild(i).gameObject;
            if(child.layer == layer) {
                child.layer = replacelayer;
            } else if(!checkLayer)
                child.layer = replacelayer;

            IterationReplace(obj.GetChild(i), checkLayer);
        }
    }
}