Unity编辑器(Editor)的问题全解以及使用

最近写了一个Unity优化工具,主要是搜索某一个文件夹中所有的场景和预设。如果是场景的话,就遍历场景中的所有对象,观察对象身上是否绑定了AudioListener组件,如果有的话移除该组件并保存场景。如果是预设的话,就遍历预设中的所有对象,观察预设中的对象是否绑定AudioListener组件,如果有的话移除该组件。

脚本如下:

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;

public class SceneOptimize : Editor {

    #region 场景优化
    //某一文件夹中的所有场景的路径,复制的场景路径用于把所有场景都复制到另一个文件夹中
    public static List<string> optimizedScenePaths;
    //某一文件夹中的所有场景的路径
    public static List<string> optimizedOriginalScenePaths;
    [MenuItem("Tools/场景优化")]
    public static void CopyAndOptimizeScenes()
    {
        //复制的场景路径
        optimizedScenePaths = new List<string>();
        //原来的场景路径
        optimizedOriginalScenePaths = new List<string>();
        //项目的路径,eg:D:/Project/Test/Assets
        string headPath = Application.dataPath;
        //Debug.Log(headPath);
        //Debug.Log(headPath.IndexOf("Assets"));
        //eg:D:/Project/Test/
        headPath = headPath.Substring(0, headPath.IndexOf("Assets"));
        Debug.Log(headPath);

        try
        {
            //复制场景到另一个文件夹中
            //CopyAllScenes("Assets/Level", "Assets/Level_optimized", headPath);
            //获取某一文件夹中所有场景的Path信息
            AddRootSourcePathToList("Assets/Level", headPath, "Scene", ref optimizedOriginalScenePaths);
        }
        catch (System.Exception e)
        {
            PlayerPrefs.SetInt("ModifySaving", 0);
            Debug.LogError(e);
        }
        
        //遍历出所有场景的路径
        for (int i = 0; i < optimizedOriginalScenePaths.Count; i++)
        {
            PlayerPrefs.SetInt("ModifySaving", 0);
            //显示遍历场景时候的进度条
            EditorUtility.DisplayCancelableProgressBar("Scene Optimizing Bar", "Save And Optimize Scenes" + i + "/" + optimizedOriginalScenePaths.Count, (float)i / optimizedOriginalScenePaths.Count);
            try
            {
                Debug.Log(optimizedOriginalScenePaths[i]);
                //获取到场景的完整路径
                string tempPath = headPath + "Assets/Level/";
                Debug.Log("tempPath :" + tempPath);
                //只获取场景的名字(eg:Main.unity,Main场景的全称)
                string tempScene = optimizedOriginalScenePaths[i].Substring(tempPath.Length);
                Debug.Log("tempScene:" + tempScene);
                //增加判断条件,对于不需要做修改的场景
                if(tempScene == "Main.unity")
                {
                    Debug.Log("Continue");
                    continue;
                }
                //打开场景
                EditorSceneManager.OpenScene(optimizedOriginalScenePaths[i], OpenSceneMode.Single);
                //开始优化
                AudioListenerOptimize();
                PlayerPrefs.SetInt("ModifySaving", 1);
                //保存修改之后的场景
                EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
            }
            catch (System.Exception e)
            {
                PlayerPrefs.SetInt("ModifySaving", 0);
                //如果发生错误,要关闭加载时候显示的滚动条
                EditorUtility.ClearProgressBar();
                Debug.Log(e);
            }
        }
        //加载完毕,关闭滚动条
        EditorUtility.ClearProgressBar();
        Debug.Log("finished");
        PlayerPrefs.SetInt("ModifySaving", 0);
    }
    //对于要修改的内容
    public static void AudioListenerOptimize()
    {
        //获取一个场景中所有的绑定了AudioListener对象
        AudioListener[] audios = FindObjectsOfType<AudioListener>();
        for (int i = 0; i < audios.Length; i++)
        {
            if (audios[i] is AudioListener)
            {
                //移除对象身上的AudioListener组件
                DestroyImmediate(audios[i].GetComponent<AudioListener>(),true);
            }
        }
    }

    /// <summary>
    /// 复制场景到另一个文件夹中
    /// </summary>
    /// <param name="rootPath"></param>
    /// <param name="targetPath"></param>
    /// <param name="headPath"></param>
    public static void CopyAllScenes(string rootPath, string targetPath, string headPath)
    {
        if (Directory.Exists(rootPath))
        {
            string[] guids;
            guids = AssetDatabase.FindAssets("t:Scene", new[] { rootPath });
            foreach (string guid in guids)
            {
                Debug.Log("guid: " + guid);
                string source = AssetDatabase.GUIDToAssetPath(guid);
                Debug.Log("source: " + source);
                string dest = source;
                Debug.Log("dest: " + dest);

                for (int i = 0; i < CountSubString("Level", "/") + 2; i++)
                {
                    Debug.Log("dest.IndexOf: " + dest.IndexOf("/"));
                    dest = dest.Substring(dest.IndexOf("/") + 1);
                }

                dest = "/" + dest;
                Debug.Log("dest: " + dest);
                dest = targetPath + dest;
                Debug.Log("dest: " + dest);

                CopySingleScene(source, dest, headPath);
            }
        }
        else
        {
            Debug.Log("No source path");
        }
    }

    public static void CopySingleScene(string source, string dest, string headPath)
    {
        source = headPath + source;
        dest = headPath + dest;

        string destDirectory = dest.Substring(0, dest.LastIndexOf("/"));
        if (!Directory.Exists(destDirectory))
        {
            Directory.CreateDirectory(destDirectory);
        }
        dest = dest.Substring(0, dest.LastIndexOf(".")) + "_Optimized.unity";
        File.Copy(source, dest, true);
        optimizedScenePaths.Add(dest);
    }

    public static int CountSubString(string targetString, string subString)
    {
        int p = 0;
        while (targetString.Contains(subString))
        {
            p++;
            targetString = targetString.Substring(targetString.IndexOf(subString) + 1);
        }
        Debug.Log("p:" + p);
        return p;
    }
    #endregion

    /// <summary>
    /// 根据在固定文件夹中的路径,根据类型(type)搜索该文件夹中的所符合的对象,然后把这些对象的路径添加到array中
    /// </summary>
    /// <param name="rootPath">目标文件路径(eg:Assets/Scenes)</param>
    /// <param name="headPath">项目路径(eg:D:Project/Test/)</param>
    /// <param name="searchType">搜索类型(Scene(搜索的是场景),Prefab(搜多的是预设))</param>
    /// <param name="array"></param>
    public static void AddRootSourcePathToList(string rootPath, string headPath, string searchType, ref List<string> array)
    {
        if (Directory.Exists(rootPath))
        {
            string[] guids;
            //搜索
            guids = AssetDatabase.FindAssets("t:" + searchType, new[] { rootPath });
            foreach (string guid in guids)
            {
                string source = AssetDatabase.GUIDToAssetPath(guid);
                //path:(D:Project/Test/Assets/Scenes/Main.unity)
                string path = headPath + source;
                array.Add(path);
            }
        }
        else
        {
            Debug.LogError("No Find Source Path");
        }
    }

    #region Prefab优化
    public static List<string> optimizePrefabsList;
    [MenuItem("Tools/预设优化")]
    public static void OptimizePrefabs()
    {
        optimizePrefabsList = new List<string>();
        string headPath = Application.dataPath;
        headPath = headPath.Substring(0, headPath.IndexOf("Assets"));
        Debug.Log(headPath);
        try
        {
            AddRootSourcePathToList("Assets/CurPrefabs", headPath,"Prefab",ref optimizePrefabsList);
        }
        catch (System.Exception e)
        {
            Debug.LogError(e);
        }
        Debug.Log("optimizePrefabsList:" + optimizePrefabsList.Count);
        for (int i = 0; i < optimizePrefabsList.Count; i++)
        {
            Debug.Log(optimizePrefabsList[i]);
            EditorUtility.DisplayCancelableProgressBar("Prefabs Optimizing Bar", "Save And Optimize Prefabs" + i + "/" + optimizePrefabsList.Count, (float)i / optimizePrefabsList.Count);
            //tempPath(eg:Assets/Prefabs/Cube.prefab)
            string tempPath = optimizePrefabsList[i].Substring(headPath.Length);
            //根据路径找到对象
            GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(tempPath);
            //Debug.Log(tempPath);
            //Debug.Log(prefab.name);
            OptimizePrefabRemoveAudioListener(prefab);
        }
        EditorUtility.ClearProgressBar();
        Debug.Log("finished");
    }

    public static void OptimizePrefabRemoveAudioListener(GameObject prefab)
    {
        AudioListener[] audios = prefab.GetComponentsInChildren<AudioListener>();
        Debug.Log(audios.Length);
        for (int i = 0; i < audios.Length; i++)
        {
            Debug.Log(audios[i].name);
            DestroyImmediate(audios[i].GetComponent<AudioListener>(),true);
        }
    }
    #endregion
}

下面分析Editor中的问题:

1,Unity中的Editor的基础篇:

https://blog.csdn.net/qq_33337811/article/details/72852342

2,Unity编辑器不用实例化Prefab获取,删除,更新组件:

http://www.360doc.com/content/16/0815/14/110467_583372012.shtml

3,根据对象名字,标签或者类型查找某一个文件夹中所有对象的路径

AssetDatabase-FindAssets的解析:http://blog.sina.com.cn/s/blog_17148af6d0102wzad.html

4,游戏运行的时候对场景中对象的修改,通过代码控制保存的方法

https://blog.csdn.net/tlrainty/article/details/77750706

5,脚本自动定位选择Hierarchy或Project下的对象

https://blog.csdn.net/qq_33337811/article/details/78858711

6,Unity编辑器扩展(自动保存当前打开的场景)

https://blog.csdn.net/crazyape/article/details/78803549

7,移除某个对象身上绑定的组件:

DestroyImmediate(audios[i].GetComponent<AudioListener>());

为了安全起见,我们移除的时候要添加一个参数:

对于Prefab身上的组件我们不能用DestroyImmediate(audios[i].GetComponent<AudioListener>());

方法,会报错。用DestroyImmediate(audios[i].GetComponent<AudioListener>(), true);方法

猜你喜欢

转载自blog.csdn.net/MonoBehaviour/article/details/81568157