预设删除Missing空脚本

方法一 : 遍历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(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(true);
        Component[] components = go.GetComponents();
        int r = 0;
        List indexer = new List();
        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();
        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();
            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("清理完成!");
    }
  1. 打开注释,从照片Resources.FindObjectsOfTypeAll()还会在Library目录中查找,所以效率上来说要比方法一快得多。
  2. 如果Resources.FindObjectsOfTypeAll()改成GameObject.FindObjectOfType()会怎么样呢,经测试它只会查找当前打开的场景中的Hierarchy面板中查找,达不到查找的效果。
    参考
  • Unity3D编辑器:删掉MissingScirpt脚本
  • Unity 删除missing脚本组件
方法三: 读取.prefab文件(未试)

参考

  • Unity bug3_删除预设上的丢失脚本Missing
  • 文件流方式 删除prefab空脚本
  • YAML Class ID Reference

你可能感兴趣的:(预设删除Missing空脚本)