Unity检查丢失引用的资源Missing

发表于2018-09-07
评论0 6.3k浏览
在修改预制体时,会经常删除原本脚本引用到的节点,这会到导致脚本中变量的引用丢失,针对这类引用的资源Missing丢失问题,下面给出了相应的解决办法。

一、用到的API

1.AssetDatabase.GetAllAssetPaths()获取unity Assets/文件下的所有资源的路径

2.AssetDatabase.LoadAssetAtPath<>(str) 根据路径加载一个资源

3、SerializedObject so=new SerializedObject(Object) 创建一个可序列化对象
var iter=so.GetIterator() 获取这个对象的迭代器 可以用iter.NextVisiable(true) 来判断有没有下一个属性
iter.propertyType 属性的类型
iter.objectReferenceValue 引用类型的属性引用的对象
iter.objectReferenceInstanceIDValue 不等于0时说明有引用对象 此时若objectReferenceValue为空 则说明Missing了

二、编辑器代码
//要继承EditorWindow才能显示自己的框框
public class FindMissingWindow : EditorWindow
    {
        [MenuItem("Tools/检查/检查MissingReference资源")]
        public static void FindMissing()
        {
            GetWindow<FindMissingWindow>().titleContent = new GUIContent("查找Missing资源");
            GetWindow<FindMissingWindow>().Show();
            Find();
        }
        private static Dictionary<UnityEngine.Object, List<UnityEngine.Object>> prefabs = new Dictionary<UnityEngine.Object, List<UnityEngine.Object>>();
        private static Dictionary<UnityEngine.Object, string> refPaths = new Dictionary<UnityEngine.Object, string>();
        private static void Find()
        {
            prefabs.Clear();
            string[] allassetpaths = AssetDatabase.GetAllAssetPaths();//获取所有资源路径
            var gos = allassetpaths
                .Where(a => a.EndsWith("prefab"))//筛选 是以prefab为后缀的 预设体资源
                .Select(a => AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(a));//加载这个预设体
                //gos拿到的是所有加载好的预设体
            foreach (var item in gos)
            {
                GameObject go = item as GameObject;
                if (go)
                {
                    Component[] cps = go.GetComponentsInChildren<Component>(true);//获取这个物体身上所有的组件
                    foreach (var cp in cps)//遍历每一个组件
                    {
                        if (!cp)
                        {
                            if (!prefabs.ContainsKey(go))
                            {
                                prefabs.Add(go, new List<UnityEngine.Object>() { cp });
                            }
                            else
                            {
                                prefabs[go].Add(cp);
                            }
                            continue;
                        }
                        SerializedObject so = new SerializedObject(cp);//生成一个组件对应的S俄日阿里则对Object对象 用于遍历这个组件的所有属性
                        var iter = so.GetIterator();//拿到迭代器
                        while (iter.NextVisible(true))//如果有下一个属性
                        {
                        //如果这个属性类型是引用类型的
                            if (iter.propertyType == SerializedPropertyType.ObjectReference)
                            {
                            //引用对象是null 并且 引用ID不是0 说明丢失了引用
                                if (iter.objectReferenceValue == null && iter.objectReferenceInstanceIDValue != 0)
                                {
                                    if (!refPaths.ContainsKey(cp)) refPaths.Add(cp, iter.propertyPath);
                                    else refPaths[cp] += " | " + iter.propertyPath;
                                    if (prefabs.ContainsKey(go))
                                    {
                                        if(!prefabs[go].Contains(cp))prefabs[go].Add(cp);
                                    }
                                    else
                                    {
                                        prefabs.Add(go, new List<UnityEngine.Object>() { cp });
                                    }
                                }
                            }
                        }
                    }
                }
            }
            EditorUtility.DisplayDialog("", "就绪", "OK");
        }
         //以下只是将查找结果显示
        private Vector3 scroll = Vector3.zero;
        private void OnGUI()
        {
            scroll = EditorGUILayout.BeginScrollView(scroll);
            EditorGUILayout.BeginVertical();
            if (GUILayout.Button("移除丢失引用的Animator组件")) RemoveAnimatorWithMissReference();
            foreach (var item in prefabs)
            {
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.ObjectField(item.Key, typeof(GameObject), true, GUILayout.Width(200));
                EditorGUILayout.BeginVertical();
                foreach (var cp in item.Value)
                {
                    if (cp)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.ObjectField(cp, cp.GetType(), true, GUILayout.Width(200));
                        if (refPaths.ContainsKey(cp))
                        {
                            GUILayout.Label(refPaths[cp]);
                        }
                        EditorGUILayout.EndHorizontal();
                    }
                }
                EditorGUILayout.EndVertical();
                EditorGUILayout.EndHorizontal();
            }
            EditorGUILayout.EndVertical();
            EditorGUILayout.EndScrollView();
        }
        private void RemoveAnimatorWithMissReference()
        {
            int count = 0;
            foreach (var cps in prefabs.Values)
            {
                foreach (var item in cps)
                {
                    Animator a = item as Animator;
                    if (a)
                    {
                        count++;
                        EditorUtility.SetDirty(a.gameObject);
                        DestroyImmediate(a, true);
                    }
                }
            }
            if (count > 0)
            {
                EditorUtility.DisplayDialog("", "一共移除" + count + "个Animator组件", "OK");
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                Find();
            }
        }
    }
来自:https://blog.csdn.net/qq_28663903/article/details/79287938

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引