unity实现批量删除Prefab上Miss的脚本组件

感谢: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是对应的,如果不对应会报以上错误。

猜你喜欢

转载自www.cnblogs.com/luguoshuai/p/12323186.html