FindSelectedPrefabImages.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using UnityEngine;
  2. using UnityEditor;
  3. using UnityEngine.UI;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. public class FindSelectedPrefabImages : EditorWindow
  8. {
  9. private string targetFolder = "D:/FB/XiuXianGame/美术/art_use_ui/all"; // 指定外部图片目录(可修改)
  10. private Vector2 scrollPosition;
  11. [MenuItem("Tools/查找选中预制件中的Sprite图片名称")]
  12. public static void ShowWindow()
  13. {
  14. // 显示编辑器窗口
  15. GetWindow<FindSelectedPrefabImages>("查找Sprite图片名称");
  16. }
  17. void OnGUI()
  18. {
  19. GUILayout.Label("查找选中预制件中的Sprite图片名称(包括隐藏和所有深层子节点)并删除不匹配的图片", EditorStyles.boldLabel);
  20. // 输入外部目标文件夹路径
  21. GUILayout.Label("外部图片文件夹路径(例如 D:/Images):");
  22. targetFolder = EditorGUILayout.TextField(targetFolder);
  23. if (GUILayout.Button("查找Sprite图片名称并删除不匹配图片"))
  24. {
  25. DeleteNonMatchingImages();
  26. }
  27. }
  28. private void GetName(GameObject obj, HashSet<string> spriteFileNames)
  29. {
  30. // 查找该对象及其所有子对象(包括深层子节点)的Image组件,包括非活跃的
  31. MyImage img = obj.GetComponent<MyImage>();
  32. if (img != null )
  33. {
  34. // 获取Sprite的资源路径
  35. // string spritePath = AssetDatabase.GetAssetPath(img.sprite);
  36. if (!string.IsNullOrEmpty(img.icon_name) && img.icon_name != "")
  37. {
  38. spriteFileNames.Add(img.icon_name);
  39. }
  40. }
  41. List<Transform> images = obj.GetComponentsInChildren<Transform>(true)?.ToList();
  42. if(images != null && images.Count > 0)
  43. {
  44. images.Remove(obj.transform);
  45. foreach (var myImage in images)
  46. {
  47. // if (myImage.sprite != null)
  48. {
  49. GetName(myImage.gameObject, spriteFileNames);
  50. }
  51. }
  52. }
  53. }
  54. private void DeleteNonMatchingImages()
  55. {
  56. // 获取当前选中的对象
  57. GameObject[] selectedObjects = Selection.gameObjects;
  58. if (selectedObjects.Length == 0)
  59. {
  60. Debug.LogWarning("没有选中任何对象!");
  61. return;
  62. }
  63. // 存储Sprite图片的文件名(不含扩展名,忽略大小写)
  64. HashSet<string> spriteFileNames = new HashSet<string>(System.StringComparer.OrdinalIgnoreCase);
  65. // 查找所有引用的Sprite
  66. foreach (GameObject obj in selectedObjects)
  67. {
  68. // 检查是否为预制件
  69. if (PrefabUtility.IsPartOfAnyPrefab(obj))
  70. {
  71. GetName(obj, spriteFileNames);
  72. // 查找该对象及其所有子对象(包括深层子节点)的Image组件,包括非活跃的
  73. // MyImage[] images = obj.GetComponentsInChildren<MyImage>(true);
  74. // foreach (MyImage img in images)
  75. // {
  76. // if (img.sprite != null)
  77. // {
  78. // // 获取Sprite的资源路径
  79. // string spritePath = AssetDatabase.GetAssetPath(img.sprite);
  80. // if (!string.IsNullOrEmpty(spritePath))
  81. // {
  82. // // 提取文件名(不含扩展名)
  83. // string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(spritePath);
  84. // spriteFileNames.Add(fileNameWithoutExtension);
  85. // // 记录GameObject的层级路径、深度和活跃状态
  86. // string hierarchyPath = GetGameObjectPath(img.gameObject);
  87. // int depth = GetHierarchyDepth(img.gameObject);
  88. // bool isActive = img.gameObject.activeInHierarchy;
  89. // Debug.Log($"找到Sprite: {img.gameObject.name}, 文件名: {fileNameWithoutExtension}, 路径: {spritePath}, 层级: {hierarchyPath}, 层级深度: {depth}, 活跃状态: {(isActive ? "显示" : "隐藏")}");
  90. // }
  91. // }
  92. // }
  93. }
  94. }
  95. if (spriteFileNames.Count == 0)
  96. {
  97. Debug.LogWarning("选中的预制件中没有找到任何Sprite图片。");
  98. return;
  99. }
  100. // 输出所有找到的Sprite文件名
  101. Debug.Log($"找到的Sprite图片文件名: {string.Join(", ", spriteFileNames)}");
  102. // 检查外部目标文件夹是否存在
  103. if (!Directory.Exists(targetFolder))
  104. {
  105. Debug.LogError($"外部目标文件夹 {targetFolder} 不存在!");
  106. return;
  107. }
  108. // 获取目标文件夹中的所有图片文件
  109. string[] imageExtensions = { "*.png", "*.jpg", "*.jpeg", "*.tga" };
  110. List<string> allImageFiles = new List<string>();
  111. foreach (string ext in imageExtensions)
  112. {
  113. allImageFiles.AddRange(Directory.GetFiles(targetFolder, ext, SearchOption.AllDirectories)
  114. .Select(path => path.Replace("\\", "/"))); // 统一路径分隔符
  115. }
  116. // 找出需要删除的图片(文件名不匹配Sprite文件名)
  117. List<string> filesToDelete = allImageFiles
  118. .Where(file =>
  119. {
  120. string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
  121. return !spriteFileNames.Contains(fileNameWithoutExtension);
  122. })
  123. .ToList();
  124. if (filesToDelete.Count == 0)
  125. {
  126. Debug.Log("外部目录中没有需要删除的图片文件(所有图片文件名均匹配Sprite文件名)。");
  127. return;
  128. }
  129. // 确认删除
  130. if (EditorUtility.DisplayDialog("确认删除",
  131. $"将要删除 {filesToDelete.Count} 个文件名不匹配Sprite图片的图片文件,是否继续?", "确定", "取消"))
  132. {
  133. int deletedCount = 0;
  134. foreach (string file in filesToDelete)
  135. {
  136. try
  137. {
  138. File.Delete(file);
  139. Debug.Log($"已删除图片: {file}");
  140. deletedCount++;
  141. }
  142. catch (System.Exception e)
  143. {
  144. Debug.LogError($"删除图片失败: {file}, 错误: {e.Message}");
  145. }
  146. }
  147. Debug.Log($"删除完成,共删除 {deletedCount} 个图片文件。");
  148. }
  149. else
  150. {
  151. Debug.Log("取消删除操作。");
  152. }
  153. }
  154. // 获取GameObject的层级路径(用于显示递归层级)
  155. private string GetGameObjectPath(GameObject obj)
  156. {
  157. string path = obj.name;
  158. while (obj.transform.parent != null)
  159. {
  160. obj = obj.transform.parent.gameObject;
  161. path = obj.name + "/" + path;
  162. }
  163. return path;
  164. }
  165. // 计算GameObject的层级深度(根节点为0)
  166. private int GetHierarchyDepth(GameObject obj)
  167. {
  168. int depth = 0;
  169. while (obj.transform.parent != null)
  170. {
  171. obj = obj.transform.parent.gameObject;
  172. depth++;
  173. }
  174. return depth;
  175. }
  176. }