最近写了一个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);方法