using UnityEngine; using UnityEditor; using System.Collections.Generic; public class AtlasAutoSplitter : EditorWindow { Texture2D sourceTexture; Color32[] pixels; int width, height; bool[,] visited; [MenuItem("Tools/Atlas Auto Splitter")] static void Open() { GetWindow("Atlas Splitter"); } void OnGUI() { sourceTexture = (Texture2D)EditorGUILayout.ObjectField("图集 Texture2D", sourceTexture, typeof(Texture2D), false); if (sourceTexture == null) return; if (GUILayout.Button("开始自动分割")) { SplitAtlas(); } } void SplitAtlas() { string path = AssetDatabase.GetAssetPath(sourceTexture); TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter; if (importer == null) { Debug.LogError("无法获取 TextureImporter"); return; } // 强制读取像素 importer.isReadable = true; // 如果不是 Multiple,自动改 if (importer.spriteImportMode != SpriteImportMode.Multiple) { importer.spriteImportMode = SpriteImportMode.Multiple; } // 应用修改并重新加载 AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate); sourceTexture = AssetDatabase.LoadAssetAtPath(path); width = sourceTexture.width; height = sourceTexture.height; pixels = sourceTexture.GetPixels32(); visited = new bool[width, height]; List metas = new List(); for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { if (visited[x, y]) continue; if (!IsSolidPixel(x, y)) { visited[x, y] = true; continue; } // 找到一个区域,开始 FloodFill Rect rect = FloodFill(x, y); SpriteMetaData meta = new SpriteMetaData(); meta.name = $"sprite_{metas.Count}"; // 修正坐标系:Unity 的 rect 原点在左下角 meta.rect = new Rect(rect.x, height - rect.y - rect.height, rect.width, rect.height); meta.pivot = new Vector2(0.5f, 0.5f); meta.alignment = (int)SpriteAlignment.Center; // 必须设置 metas.Add(meta); } } importer.spritesheet = metas.ToArray(); // 确保写入并刷新 EditorUtility.SetDirty(importer); AssetDatabase.WriteImportSettingsIfDirty(path); AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate); AssetDatabase.Refresh(); Debug.Log($"分割完成,共生成 {metas.Count} 个 Sprite"); } bool IsSolidPixel(int x, int y) { Color32 c = pixels[y * width + x]; return c.a > 10; // 透明度阈值 } Rect FloodFill(int startX, int startY) { Queue q = new Queue(); q.Enqueue(new Vector2Int(startX, startY)); int minX = startX, maxX = startX; int minY = startY, maxY = startY; visited[startX, startY] = true; while (q.Count > 0) { Vector2Int p = q.Dequeue(); int x = p.x; int y = p.y; // 更新边界 if (x < minX) minX = x; if (x > maxX) maxX = x; if (y < minY) minY = y; if (y > maxY) maxY = y; // 四方向扩散 TryAdd(x + 1, y, q); TryAdd(x - 1, y, q); TryAdd(x, y + 1, q); TryAdd(x, y - 1, q); } // 注意 Unity 的 rect 是左下角为原点 return new Rect(minX, minY, maxX - minX + 1, maxY - minY + 1); } void TryAdd(int x, int y, Queue q) { if (x < 0 || x >= width || y < 0 || y >= height) return; if (visited[x, y]) return; visited[x, y] = true; if (!IsSolidPixel(x, y)) return; q.Enqueue(new Vector2Int(x, y)); } }