感谢:https://www.cnblogs.com/AaronBlogs/p/7976054.html
我的unity版本: unity2017.2.0p4
本篇文章将根据我个人的实践进行记录,有些情况也许没有考虑进去。随着unity版本的提升,也许会有现成的api可以直接实现(像unity2019中的GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go),具体没有测试)
实现目标:
到 ,并且在后续的操作中图一的情况不会恢复。
先说明一下,miss脚本的两种情况:
在Inpsector面板中看起来是这样的,打开对应的prefab文件,继续往下看内在的区别。
执行工具后,prefab文件的变化成了下面的结构:
下面贴上代码:
1 using System; 2 using System.IO; 3 using System.Collections; 4 using System.Collections.Generic; 5 using UnityEngine; 6 using UnityEditor; 7 using System.Text.RegularExpressions; 8 9 namespace LgsProject 10 { 11 public partial class LgsTools_Optimization 12 { 13 [MenuItem("LgsTools/智能检测/Remove Missing-MonoBehavior Component")] 14 static public void RemoveMissComponent() 15 { 16 string fullPath = Application.dataPath + "/Art/Prefabs"; 17 fullPath = fullPath.Replace("/", @"\"); 18 List<string> pathList = GetAssetsPath(fullPath, "*.prefab", SearchOption.AllDirectories); 19 int counter = 0; 20 for (int i = 0, iMax = pathList.Count; i < iMax; i++) 21 { 22 EditorUtility.DisplayProgressBar("处理进度", string.Format("{0}/{1}", i + 1, iMax), (i + 1f) / iMax); 23 if (CheckMissMonoBehavior(pathList[i])) 24 ++counter; 25 } 26 EditorUtility.ClearProgressBar(); 27 EditorUtility.DisplayDialog("处理结果", "完成修改,修改数量 : " + counter, "确定"); 28 AssetDatabase.Refresh(); 29 } 30 31 /// <summary> 32 /// 获取某种资源的路径 33 /// </summary> 34 /// <param name="fullPath">例如 : Application.dataPath + "/Art/Prefabs" </param> 35 /// <param name="filter">例如 : *.prefab</param> 36 /// <param name="searchOption">目录的搜索方式</param> 37 /// <returns></returns> 38 static List<string> GetAssetsPath(string fullPath, string filter, SearchOption searchOption) 39 { 40 List<string> pathList = new List<string>(); 41 string[] files = Directory.GetFiles(fullPath, filter, searchOption); 42 for (int i = 0; i < files.Length; i++) 43 { 44 string path = files[i]; 45 path = "Assets" + path.Substring(Application.dataPath.Length, path.Length - Application.dataPath.Length); 46 pathList.Add(path); 47 } 48 49 return pathList; 50 } 51 52 /// <summary> 53 /// 删除一个Prefab上的空脚本 54 /// </summary> 55 /// <param name="path">prefab路径 例Assets/Resources/FriendInfo.prefab</param> 56 static bool CheckMissMonoBehavior(string path) 57 { 58 bool isNull = false; 59 string s = File.ReadAllText(path); 60 Regex regBlock = new Regex("MonoBehaviour"); 61 // 以"---"划分组件 62 string[] strArray = s.Split(new string[] { "---" }, StringSplitOptions.RemoveEmptyEntries); 63 for (int i = 0; i < strArray.Length; i++) 64 { 65 string blockStr = strArray[i]; 66 if (regBlock.IsMatch(blockStr)) 67 { 68 // 模块是 MonoBehavior 69 Match guidMatch = Regex.Match(blockStr, "m_Script: {fileID: (.*), guid: (?<GuidValue>.*?), type:"); 70 Match guidMatch_1 = Regex.Match(blockStr, "m_Script: {fileID: (.*)"); 71 72 if (guidMatch.Success || guidMatch_1.Success) 73 { 74 // 获取 MonoBehavior的guid 75 string guid = guidMatch.Groups["GuidValue"].Value; 76 Debug.Log("Guid:" + guid); 77 string tempPath = AssetDatabase.GUIDToAssetPath(guid); 78 79 if (string.IsNullOrEmpty(tempPath) || !File.Exists(tempPath)) 80 { 81 isNull = true; 82 // 删除操作 83 // 删除MonoScript 84 s = s.Replace("---" + blockStr, ""); 85 Match idMatch = Regex.Match(blockStr, "!u!(.*) &(?<idValue>.*?)\n"); 86 if (idMatch.Success) 87 { 88 // 获取 MonoBehavior的guid 89 string id = idMatch.Groups["idValue"].Value; 90 // 删除MonoScript的引用 91 Regex quote = new Regex(" - (.*): {fileID: " + id + "}\n"); 92 s = quote.Replace(s, ""); 93 } 94 } 95 } 96 } 97 } 98 if (isNull) 99 { 100 // 有空脚本 写回prefab 101 File.WriteAllText(path, s); 102 } 103 return isNull; 104 } 105 } 106 }
另外,在实践的过程中遇到了一个报错,顺便记录一下:
CheckConsistency: GameObject does not reference component MonoBehaviour. Fixing.
看下图,正常情况下prefab文件中区域1和区域2是对应的,如果不对应会报以上错误。