方法一 : 遍历AssetDatabase资源
[MenuItem("Assets/DelectMissingScript/All")]
public static void DelectAllNullReference()
{
string[] guids = AssetDatabase.FindAssets("t:prefab");
foreach(string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
GameObject newObj = AssetDatabase.LoadAssetAtPath<GameObject>(path);
FindMissing(newObj, path);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
[MenuItem("Assets/DelectMissingScript/Single")]
public static void DelectSingleReference()
{
GameObject go = Selection.activeGameObject;
string path = AssetDatabase.GetAssetPath(go);
FindMissing(go, path);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private static void FindMissing(GameObject go, string path)
{
int sum = 0;
FindMissing(go, true, ref sum);
}
private static void FindMissing(GameObject go, bool refresh, ref int sum)
{
var tt = go.GetComponentsInChildren<Component>(true);
Component[] components = go.GetComponents<Component>();
int r = 0;
List<int> indexer = new List<int>();
for (int j = 0, len = components.Length; j < len; j++)
{
if (components[j] != null)
continue;
indexer.Add(j);
r++;
sum++;
}
if (r > 0)
{
r = 0;
SerializedObject so = new SerializedObject(go);
SerializedProperty property = so.FindProperty("m_Component");
foreach(int idx in indexer)
{
int i = idx - r; //这个地方要注意,删除时索引会减1
property.DeleteArrayElementAtIndex(i);
r++;
}
so.ApplyModifiedProperties();
}
foreach (Transform child in go.transform)
{
FindMissing(child.gameObject, false, ref sum);
}
if(sum > 0 && refresh)
{
EditorUtility.SetDirty(go);
AssetDatabase.SaveAssets();
}
}
注意点
- 一定要遍历完
Component[]
, 如果有null则property.DeleteArrayElementAtIndex
,最终才能标记EditorUtility.SetDirty(go)
,不然AssetDatabase.SaveAssets()
保存失败而报错
方法二 : Resources.FindObjectsOfTypeAll遍历资源
[MenuItem("Assets/移除丢失的脚本")]
public static void RemoveMissingScript()
{
var gos = Resources.FindObjectsOfTypeAll<GameObject>();
foreach (var item in gos)
{
// Debug.Log(AssetDatabase.GetAssetPath(item));
SerializedObject so = new SerializedObject(item);
var soProperties = so.FindProperty("m_Component");
var components = item.GetComponents<Component>();
int propertyIndex = 0;
int index = 0;
foreach (var c in components)
{
if (c == null)
{
soProperties.DeleteArrayElementAtIndex(index - propertyIndex);
++propertyIndex;
}
index++;
}
so.ApplyModifiedProperties();
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("清理完成!");
}
- 打开注释,从照片
Resources.FindObjectsOfTypeAll()
还会在Library
目录中查找,所以效率上来说要比方法一快得多。 - 如果
Resources.FindObjectsOfTypeAll()
改成GameObject.FindObjectOfType<GameObject>()
会怎么样呢,经测试它只会查找当前打开的场景中的Hierarchy面板
中查找,达不到查找的效果。
参考
方法三: 读取.prefab文件(未试)
参考