FindSelectedPrefabImages.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. if (GUILayout.Button("开始替换"))
  28. {
  29. ReplaceImagesInPrefabs(targetFolder);
  30. }
  31. }
  32. private void ReplaceImagesInPrefabs(string path)
  33. {
  34. string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { path });
  35. foreach (string guid in guids)
  36. {
  37. string assetPath = AssetDatabase.GUIDToAssetPath(guid);
  38. GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
  39. if (prefab == null) continue;
  40. GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
  41. bool changed = false;
  42. MyImage[] images = instance.GetComponentsInChildren<MyImage>(true);
  43. foreach (var img in images)
  44. {
  45. img.UseGradient = false;
  46. changed = true;
  47. }
  48. if (changed)
  49. {
  50. PrefabUtility.SaveAsPrefabAsset(instance, assetPath);
  51. Debug.Log($"更新了预制件:{assetPath}");
  52. }
  53. DestroyImmediate(instance);
  54. }
  55. AssetDatabase.Refresh();
  56. Debug.Log("替换完成!");
  57. }
  58. private void GetName(GameObject obj, HashSet<string> spriteFileNames)
  59. {
  60. // 查找该对象及其所有子对象(包括深层子节点)的Image组件,包括非活跃的
  61. MyImage img = obj.GetComponent<MyImage>();
  62. if (img != null)
  63. {
  64. // 获取Sprite的资源路径
  65. // string spritePath = AssetDatabase.GetAssetPath(img.sprite);
  66. if (!string.IsNullOrEmpty(img.icon_name) && img.icon_name != "")
  67. {
  68. spriteFileNames.Add(img.icon_name);
  69. }
  70. }
  71. List<Transform> images = obj.GetComponentsInChildren<Transform>(true)?.ToList();
  72. if (images != null && images.Count > 0)
  73. {
  74. images.Remove(obj.transform);
  75. foreach (var myImage in images)
  76. {
  77. // if (myImage.sprite != null)
  78. {
  79. GetName(myImage.gameObject, spriteFileNames);
  80. }
  81. }
  82. }
  83. }
  84. private void DeleteNonMatchingImages()
  85. {
  86. // 获取当前选中的对象
  87. GameObject[] selectedObjects = Selection.gameObjects;
  88. if (selectedObjects.Length == 0)
  89. {
  90. Debug.LogWarning("没有选中任何对象!");
  91. return;
  92. }
  93. // 存储Sprite图片的文件名(不含扩展名,忽略大小写)
  94. HashSet<string> spriteFileNames = new HashSet<string>(System.StringComparer.OrdinalIgnoreCase);
  95. // 查找所有引用的Sprite
  96. foreach (GameObject obj in selectedObjects)
  97. {
  98. // 检查是否为预制件
  99. if (PrefabUtility.IsPartOfAnyPrefab(obj))
  100. {
  101. GetName(obj, spriteFileNames);
  102. // 查找该对象及其所有子对象(包括深层子节点)的Image组件,包括非活跃的
  103. // MyImage[] images = obj.GetComponentsInChildren<MyImage>(true);
  104. // foreach (MyImage img in images)
  105. // {
  106. // if (img.sprite != null)
  107. // {
  108. // // 获取Sprite的资源路径
  109. // string spritePath = AssetDatabase.GetAssetPath(img.sprite);
  110. // if (!string.IsNullOrEmpty(spritePath))
  111. // {
  112. // // 提取文件名(不含扩展名)
  113. // string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(spritePath);
  114. // spriteFileNames.Add(fileNameWithoutExtension);
  115. // // 记录GameObject的层级路径、深度和活跃状态
  116. // string hierarchyPath = GetGameObjectPath(img.gameObject);
  117. // int depth = GetHierarchyDepth(img.gameObject);
  118. // bool isActive = img.gameObject.activeInHierarchy;
  119. // Debug.Log($"找到Sprite: {img.gameObject.name}, 文件名: {fileNameWithoutExtension}, 路径: {spritePath}, 层级: {hierarchyPath}, 层级深度: {depth}, 活跃状态: {(isActive ? "显示" : "隐藏")}");
  120. // }
  121. // }
  122. // }
  123. }
  124. }
  125. if (spriteFileNames.Count == 0)
  126. {
  127. Debug.LogWarning("选中的预制件中没有找到任何Sprite图片。");
  128. return;
  129. }
  130. // 输出所有找到的Sprite文件名
  131. Debug.Log($"找到的Sprite图片文件名: {string.Join(", ", spriteFileNames)}");
  132. // 检查外部目标文件夹是否存在
  133. if (!Directory.Exists(targetFolder))
  134. {
  135. Debug.LogError($"外部目标文件夹 {targetFolder} 不存在!");
  136. return;
  137. }
  138. // 获取目标文件夹中的所有图片文件
  139. string[] imageExtensions = { "*.png", "*.jpg", "*.jpeg", "*.tga" };
  140. List<string> allImageFiles = new List<string>();
  141. foreach (string ext in imageExtensions)
  142. {
  143. allImageFiles.AddRange(Directory.GetFiles(targetFolder, ext, SearchOption.AllDirectories)
  144. .Select(path => path.Replace("\\", "/"))); // 统一路径分隔符
  145. }
  146. // 找出需要删除的图片(文件名不匹配Sprite文件名)
  147. List<string> filesToDelete = allImageFiles
  148. .Where(file =>
  149. {
  150. string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
  151. return !spriteFileNames.Contains(fileNameWithoutExtension);
  152. })
  153. .ToList();
  154. if (filesToDelete.Count == 0)
  155. {
  156. Debug.Log("外部目录中没有需要删除的图片文件(所有图片文件名均匹配Sprite文件名)。");
  157. return;
  158. }
  159. // 确认删除
  160. if (EditorUtility.DisplayDialog("确认删除",
  161. $"将要删除 {filesToDelete.Count} 个文件名不匹配Sprite图片的图片文件,是否继续?", "确定", "取消"))
  162. {
  163. int deletedCount = 0;
  164. foreach (string file in filesToDelete)
  165. {
  166. try
  167. {
  168. File.Delete(file);
  169. Debug.Log($"已删除图片: {file}");
  170. deletedCount++;
  171. }
  172. catch (System.Exception e)
  173. {
  174. Debug.LogError($"删除图片失败: {file}, 错误: {e.Message}");
  175. }
  176. }
  177. Debug.Log($"删除完成,共删除 {deletedCount} 个图片文件。");
  178. }
  179. else
  180. {
  181. Debug.Log("取消删除操作。");
  182. }
  183. }
  184. // 获取GameObject的层级路径(用于显示递归层级)
  185. private string GetGameObjectPath(GameObject obj)
  186. {
  187. string path = obj.name;
  188. while (obj.transform.parent != null)
  189. {
  190. obj = obj.transform.parent.gameObject;
  191. path = obj.name + "/" + path;
  192. }
  193. return path;
  194. }
  195. // 计算GameObject的层级深度(根节点为0)
  196. private int GetHierarchyDepth(GameObject obj)
  197. {
  198. int depth = 0;
  199. while (obj.transform.parent != null)
  200. {
  201. obj = obj.transform.parent.gameObject;
  202. depth++;
  203. }
  204. return depth;
  205. }
  206. }