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

脚本如下:

增加:过滤非指定资源的执行(动画代码修改:)

using ML_Animation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;

class BlendAnimation : EditorWindow
{
    public static string[] saveLimitKey = new string[] {
        //"Bip001 Footsteps",
        "Bip001 Pelvis","Bip001 Spine",
        "Bip001 L Thigh","Bip001 R Thigh",
        "Bip001 L Calf", "Bip001 R Calf",
        //"Bip001 L Foot", "Bip001 R Foot",
        //"Bip001 L Toe0","Bip001 R Toe0", "Bip001 L Toe0Nub","Bip001 R Toe0Nub",
        //"Bip001 Spine1","Bone017","Bone021",
        //"Bip001 Prop1","Dummy001"
    };
    private static StringBuilder strBuilder;
    private static OptimizeAnimationClipProperty optAnimProperty = null;

    [MenuItem("Assets/优化/动画/选中AnimationClip-ModifyHeroCameraFOV", true, 0)]
    public static bool AnimationAddProperty_()
    {
        AnimationClip clip = Selection.activeObject as AnimationClip;
        if (clip == null)
            return false;
        else
            return true;
    }

    [MenuItem("Assets/优化/动画/选中AnimationClip-ModifyHeroCameraFOV", false, 0)]
    public static void AnimationAddProperty()
    {
        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.DeepAssets);
        int count = 0;
        foreach (UnityEngine.Object obj in objs)
        {
            ++count;
            EditorUtility.DisplayProgressBar("正在修改动画,请勿操作Unity!!!", count + "/" + objs.Length, count * 1.0f / objs.Length);
            AnimationClip clip = obj as AnimationClip;
            EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(clip);
            for (int i = 0; i < curveBindings.Length; i++)
            {
                EditorCurveBinding curveBind = curveBindings[i];
                if (curveBind.type == typeof(Camera))
                {
                    AnimationCurve animCurve = AnimationUtility.GetEditorCurve(clip, curveBind);
                    AnimationUtility.SetEditorCurve(clip, curveBind, null);
                    curveBind.path = "cam/m_3DHeroCamera";
                    AnimationUtility.SetEditorCurve(clip, curveBind, animCurve);

                    AnimationCurve addCurve = new AnimationCurve();
                    addCurve.AddKey(0, 0);
                    addCurve.AddKey(clip.length, 0);
                    clip.SetCurve("cam/m_3DHeroCamera", typeof(Transform), "m_LocalRotation.x", addCurve);
                    clip.SetCurve("cam/m_3DHeroCamera", typeof(Transform), "m_LocalRotation.y", addCurve);
                    clip.SetCurve("cam/m_3DHeroCamera", typeof(Transform), "m_LocalRotation.z", addCurve);
                }
            }
        }
        AssetDatabase.Refresh();
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("Assets/优化/动画/选中AnimationClip-优化动画", false, 1)]
    public static void AnimOptimizeTrilogy()
    {
        int count = 0;
        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.DeepAssets);
        foreach (UnityEngine.Object o in objs)
        {
            count++;
            EditorUtility.DisplayProgressBar("优化动画三部曲...", AssetDatabase.GetAssetPath(o), count * 1.0f / objs.Length);

            AnimationClip clip = RemoveAnimationSameKeyframe(o as AnimationClip);
            ExecuteOptimaze_(clip);
            ReduceAnimationCurve(ref clip);
        }
        AssetDatabase.SaveAssets();
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("Assets/优化/动画/选中Prefab-优化动画", false, 2)]
    public static void OptimizeAnimation()
    {
        strBuilder = new StringBuilder();
        optAnimProperty = new OptimizeAnimationClipProperty();

        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);
        for (int i = 0; i < objs.Length; i++)
        {
            EditorUtility.DisplayProgressBar("优化动画三部曲...", AssetDatabase.GetAssetPath(objs[i]), i * 1.0f / objs.Length);

            string path = AssetDatabase.GetAssetPath(objs[i]);
            string suffix = Path.GetExtension(path);
            if (suffix == ".prefab")
            {
                optAnimProperty.AllPrefabNum++;
                OptimizeAnimationClips(path);
            }
        }

        PrintLog();
        AssetDatabase.SaveAssets();
        EditorUtility.ClearProgressBar();
    }

    public static void OptimizeAnimationClips(string path)
    {
        bool isModifyAnimClip = false;
        List<string> optAnims = new List<string>();
        string[] depends = AssetDatabase.GetDependencies(path);
        for (int i = 0; i < depends.Length; i++)
        {
            if (Path.GetExtension(depends[i]) == ".anim")
            {
                if (optAnimProperty.hadOperation.Contains(depends[i]))
                {
                    continue;
                }
                else
                {
                    optAnimProperty.hadOperation.Add(depends[i]);
                    optAnims.Add(depends[i]);
                }

                AnimationClip clip = AssetDatabase.LoadAssetAtPath(depends[i], typeof(AnimationClip)) as AnimationClip;
                if (clip == null)
                {
                    Debug.LogError(depends[i] + " is not Exist");
                    continue;
                }
                clip = RemoveAnimationSameKeyframe(clip);
                ExecuteOptimaze_(clip);
                ReduceAnimationCurve(ref clip);

                optAnimProperty.ModifyAnimNum++;
                isModifyAnimClip = true;
            }
        }

        if (optAnims.Count > 0)
        {
            optAnimProperty.dicLog.Add(path, optAnims);
        }
        if (isModifyAnimClip)
            optAnimProperty.ModifyPrefabNum++;
    }

    //[MenuItem("Assets/优化/动画/精简动画小数点")]
    private static void AnimationDataOptimaze()
    {
        int number = 0;
        DateTime time = DateTime.Now;
        foreach (UnityEngine.Object o in Selection.GetFiltered(typeof(AnimationClip), SelectionMode.DeepAssets))
        {
            number++;
            ExecuteOptimaze(Instantiate(o) as AnimationClip, AssetDatabase.GetAssetPath(o));
        }
        AssetDatabase.SaveAssets();
        Debug.Log("一共压缩了" + number + "个动画文件!");
        Debug.Log("耗时:" + (DateTime.Now - time).TotalMilliseconds / 1000 + "秒.");
    }

    //[MenuItem("Assets/优化/动画/优化动画小数点,不对动画重新创建")]
    public static void OptimazeAnimationDecimalPoint()
    {
        int count = 0;
        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.DeepAssets);
        foreach (UnityEngine.Object o in objs)
        {
            count++;
            EditorUtility.DisplayProgressBar("优化动画小数点,不重新创建动画", count + "/" + objs.Length, count * 1.0f / objs.Length);
            ExecuteOptimaze_(o as AnimationClip);
        }
        EditorUtility.ClearProgressBar();
    }
    private static AnimationClip ExecuteOptimaze_(AnimationClip clip)
    {
        EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(clip);
        for (int i = 0; i < curveBindings.Length; i++)
        {
            AnimationCurve animCurve = AnimationUtility.GetEditorCurve(clip, curveBindings[i]);
            var keyFrames = animCurve.keys;
            for (int j = 0; j < keyFrames.Length; j++)
            {
                var key = keyFrames[j];
                key.value = float.Parse(key.value.ToString("f4"));
                key.inTangent = float.Parse(key.inTangent.ToString("f4"));
                key.outTangent = float.Parse(key.outTangent.ToString("f4"));
                keyFrames[j] = key;
            }
            animCurve.keys = keyFrames;
            AnimationUtility.SetEditorCurve(clip, curveBindings[i], animCurve);
        }
        //AssetDatabase.SaveAssets();
        return clip;
    }

    private static AnimationClip ExecuteOptimaze(AnimationClip clip, string clipName)
    {
        EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(clip);
        AnimationClipCurveData[] curves = new AnimationClipCurveData[curveBindings.Length];
        for (int index = 0; index < curves.Length; ++index)
        {
            curves[index] = new AnimationClipCurveData(curveBindings[index]);
            curves[index].curve = AnimationUtility.GetEditorCurve(clip, curveBindings[index]);
        }
        foreach (AnimationClipCurveData curveDate in curves)
        {
            var keyFrames = curveDate.curve.keys;
            for (int i = 0; i < keyFrames.Length; i++)
            {
                var key = keyFrames[i];
                key.value = float.Parse(key.value.ToString("f4"));
                key.inTangent = float.Parse(key.inTangent.ToString("f4"));
                key.outTangent = float.Parse(key.outTangent.ToString("f4"));
                keyFrames[i] = key;
            }
            curveDate.curve.keys = keyFrames;
            clip.SetCurve(curveDate.path, curveDate.type, curveDate.propertyName, curveDate.curve);
        }
        AssetDatabase.CreateAsset(clip, clipName);

        return clip;
    }

    private static void ControlAnimationMetaFile(string metaPath, bool bRead)
    {
        if (bRead)
        {
            strBuilder = new StringBuilder();
            FileStream fs = new FileStream(metaPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default);
            while (!sr.EndOfStream)
            {
                strBuilder.AppendLine(sr.ReadLine());
            }
            sr.Dispose();
        }
        else
        {
            if (File.Exists(metaPath))
                File.Delete(metaPath);
            StreamWriter sw = new StreamWriter(metaPath);
            sw.Write(strBuilder);
            sw.Dispose();
        }
    }

    //[MenuItem("Assets/优化/动画/移除相同关键帧")]
    public static void AnimationRemoveKeyFrame()
    {
        UnityEngine.Object[] objs = Selection.objects;
        for (int i = 0; i < objs.Length; i++)
        {
            UnityEngine.Object obj = objs[i];
            if (obj.GetType() == typeof(AnimationClip))
            {
                EditorUtility.DisplayProgressBar("移除动画相同关键帧...", AssetDatabase.GetAssetPath(obj), i * 1.0f / objs.Length);
                RemoveAnimationSameKeyframe(obj as AnimationClip);
            }
        }
        AssetDatabase.SaveAssets();
        EditorUtility.ClearProgressBar();
    }
    public static AnimationClip RemoveAnimationSameKeyframe(AnimationClip clip)
    {
        string path = AssetDatabase.GetAssetPath(clip);
        EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(clip);
        foreach (var curve in curveBindings)
        {
            AnimationCurve animCurve = AnimationUtility.GetEditorCurve(clip, curve);
            if (animCurve.keys.Length > 1 && !curve.isPPtrCurve)
            {
                Keyframe cntKeyframe = animCurve.keys[0];
                List<Keyframe> m_Keyframes = new List<Keyframe>();
                m_Keyframes.Add(cntKeyframe);
                int sameIndex = 0;
                for (int i = 1; i < animCurve.keys.Length; ++i)
                {
                    Keyframe item = animCurve.keys[i];
                    m_Keyframes.Add(item);

                    if (Mathf.Abs(item.value - cntKeyframe.value) > 0.00001f
                        || i == animCurve.keys.Length - 1
                        || Math.Abs(item.inTangent - cntKeyframe.inTangent) > 0.00001f
                        || Math.Abs(item.outTangent - cntKeyframe.outTangent) > 0.00001f
                        || item.tangentMode != cntKeyframe.tangentMode)
                    {
                        sameIndex = 0;
                    }
                    else
                    {
                        sameIndex += 1;
                    }
                    cntKeyframe = item;
                    if (sameIndex > 1)
                    {
                        m_Keyframes.RemoveAt(m_Keyframes.Count - 2);
                    }
                }

                animCurve.keys = m_Keyframes.ToArray();
                AnimationUtility.SetEditorCurve(clip, curve, animCurve);
            }
        }
        return clip;
    }

    [MenuItem("Assets/优化/动画/根据FBX(原始资源)生成混合动画", false, 3)]
    public static void AnimationOptimization()
    {
        List<AnimationClip> animClips = new List<AnimationClip>();
        UnityEngine.Object[] animObjs = Selection.objects;
        for (int i = 0; i < animObjs.Length; i++)
        {
            AnimationClip anim = animObjs[i] as AnimationClip;
            if (anim)
            {
                animClips.Add(anim);
            }
        }
        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);
        for (int i = 0; i < objs.Length; i++)
        {
            string path = AssetDatabase.GetAssetPath(objs[i]);
            string suffix = Path.GetExtension(path).ToLower();
            if (suffix == ".fbx")
            {
                GetAnimationClip(path, animClips);
            }
        }
    }

    public static void GetAnimationClip(string fbxPath, List<AnimationClip> animClips)
    {
        UnityEngine.Object[] objs = AssetDatabase.LoadAllAssetRepresentationsAtPath(fbxPath);
        AnimationClip idleClip = null;
        for (int i = 0; i < objs.Length; i++)
        {
            idleClip = objs[i] as AnimationClip;
            if (idleClip != null && !idleClip.name.ToLower().Contains("action"))
            {
                if (animClips.Count > 0)
                {
                    if (animClips.Contains(idleClip))
                        CreateBlendAnimation(idleClip, fbxPath);
                    else
                        continue;
                }
                else
                {
                    CreateBlendAnimation(idleClip, fbxPath);
                }
            }
            else
                continue;
        }
    }

    public static void CreateBlendAnimation(AnimationClip idleClip, string fbxPath)
    {
        List<AnimationClipCurveData> lstAnimClipCurve = new List<AnimationClipCurveData>();
        List<AnimationClipCurveData> lstAnimCompressClipCurve = new List<AnimationClipCurveData>();
        List<AnimationClipCurveData> lstAnimBlendClipCurve = new List<AnimationClipCurveData>();

        //AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(fbxPath);
        ModelImporter importer = AssetImporter.GetAtPath(fbxPath) as ModelImporter;
        if (idleClip == null || importer == null)
            return;

        if (importer.animationCompression != ModelImporterAnimationCompression.Off)
        {
            importer.animationCompression = ModelImporterAnimationCompression.Off;
            importer.SaveAndReimport();
        }
        AnimationClip blendAnimClip = UnityEngine.Object.Instantiate(idleClip);
        blendAnimClip.ClearCurves();

        lstAnimClipCurve = RecordAnimationCurve(idleClip);
        importer.animationCompression = ModelImporterAnimationCompression.KeyframeReduction;
        importer.SaveAndReimport();
        lstAnimCompressClipCurve = RecordAnimationCurve(idleClip);

        for (int i = 0; i < lstAnimClipCurve.Count; i++)
        {
            string[] splitPath = lstAnimClipCurve[i].path.Split('/');
            string keys = splitPath[splitPath.Length - 1];
            if (saveLimitKey.ToList().Contains(keys))
            {
                lstAnimBlendClipCurve.Add(lstAnimClipCurve[i]);
            }
            else
            {
                lstAnimBlendClipCurve.Add(lstAnimCompressClipCurve[i]);
            }
        }

        for (int i = 0; i < lstAnimBlendClipCurve.Count; i++)
        {
            AnimationClipCurveData data = lstAnimBlendClipCurve[i];
            blendAnimClip.SetCurve(data.path, data.type, data.propertyName, data.curve);
        }
        ReduceAnimationCurve(ref blendAnimClip);
        string path2 = string.Format("{0}/{1}.anim", Path.GetDirectoryName(fbxPath), idleClip.name);
        SaveAnim(blendAnimClip, path2);
    }

    /// <summary>
    /// 记录AnimationClip的曲线
    /// </summary>
    /// <param name="clip"></param>
    /// <returns></returns>
    public static List<AnimationClipCurveData> RecordAnimationCurve(AnimationClip clip)
    {
        EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(clip);
        List<AnimationClipCurveData> curveDatas = new List<AnimationClipCurveData>();

        for (int i = 0; i < curveBindings.Length; i++)
        {
            AnimationCurve animCurve = AnimationUtility.GetEditorCurve(clip, curveBindings[i]);
            AnimationClipCurveData curveData = new AnimationClipCurveData(curveBindings[i]);
            curveData.curve = animCurve;

            curveDatas.Add(curveData);
        }

        return curveDatas;
    }

    /// <summary>
    /// 移除动画不必要的曲线
    /// </summary>
    /// <param name="clip"></param>
    public static void ReduceAnimationCurve(ref AnimationClip clip)
    {
        SerializedObject serializedObject = new SerializedObject(clip);
        serializedObject.FindProperty("m_EditorCurves").arraySize = 0;
        serializedObject.FindProperty("m_EulerEditorCurves").arraySize = 0;
        //serializedObject.FindProperty("m_FloatCurves").arraySize = 0;
        serializedObject.ApplyModifiedProperties();
    }

    public static void SaveAnim(AnimationClip clip, string clipName)
    {
        if (!Directory.Exists(Path.GetDirectoryName(clipName)))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(clipName));
        }
        //clip.legacy = true;
        //clip.wrapMode = WrapMode.Loop;
        AssetDatabase.CreateAsset(clip, clipName);
        AssetDatabase.Refresh();
    }

    private static void PrintLog()
    {
        string path = Application.dataPath.Replace("Assets", "ProfilerData/AnimOptimize.txt");
        Debug.Log(path);
        if (!Directory.Exists(Path.GetDirectoryName(path)))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(path));
        }
        if (File.Exists(path))
            File.Delete(path);

        foreach (var item in optAnimProperty.dicLog)
        {
            string labelName = string.Empty;
            for (int i = 0; i < item.Value.Count; i++)
            {
                labelName += item.Value[i] + ",";
            }
            strBuilder.Append(string.Format("{0}:{1}\n", item.Key, labelName));
        }
        strBuilder.Append(string.Format("检索Prefab数量:{0}\n需要修改的Prefab数量:{1},占总量的:{2}%\n修改的Animation数量:{3}"
            , optAnimProperty.AllPrefabNum, optAnimProperty.ModifyPrefabNum, optAnimProperty.ModifyPrefabNum * 1.0f / optAnimProperty.AllPrefabNum * 100, optAnimProperty.ModifyAnimNum));
        using (StreamWriter sw = new StreamWriter(path))
        {
            sw.Write(strBuilder);
            sw.Dispose();
        }
    }
}

public class OptimizeAnimationClipProperty
{
    public int AllPrefabNum;
    public int ModifyAnimNum;
    public int ModifyPrefabNum;
    public Dictionary<string, List<string>> dicLog = null;
    public List<string> hadOperation = null;

    public OptimizeAnimationClipProperty()
    {
        dicLog = new Dictionary<string, List<string>>();
        hadOperation = new List<string>();
    }
}
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的基础篇:

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

Unity3D研究院编辑器之不实例化Prefab获取删除更新组件(十五) | 雨松MOMO程序研究院

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

AssetDatabase-FindAssets的解析:AssetDatabase-FindAssets_京畿小李_新浪博客

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

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

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


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

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

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

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

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