Unity 选择文件名~打图集

/*=================================================
*FileName:      AtlasAutoProcessor.cs 
*Author:        yrc&qww
*UnityVersion:  2021.2.18f1 
*Date:          2025-10-25 11:00 最终完成 2025-11-8: 10:23
*Description:   打图集工具 – 优化创建顺序:先prefab和mat,后png
*History:       
=================================================*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace AtlasTool
{
    public class AtlasAutoProcessor : EditorWindow
    {
        #region 配置字段
        private string sourcePath = @”源目录”;
        private string targetPath = @”临时目录”;
        private string outputPath = @”输出目录”;

        private List<string> atlasFolders = new List<string>();
        private Vector2 scrollPosition;
        private bool[] selectedFolders;

        // 处理状态
        private enum ProcessState
        {
            Idle,
            Copying,
            Importing,
            CreatingPrefabAndMat,  // 新增状态:先创建prefab和mat
            CreatingAtlas,         // 然后创建图集
            Complete
        }

        private ProcessState currentState = ProcessState.Idle;
        private Queue<string> processingQueue = new Queue<string>();
        private string currentFolder;
        private float importStartTime;
        private const float ImportWaitTime = 3f;

        // 处理进度相关
        private int totalFoldersToProcess = 0;
        private int processedFolders = 0;
        #endregion

        #region 图集设置 start
        // 图集设置参数
        private int padding = 4;
        private bool trimAlpha = true;
        private bool removeEmptySpace = true;
        private bool useUnityPacker = true;
        private bool forceTrueColor = true;
        private bool forceARGB32 = true;
        private int maxAtlasSize = 4096;

        // 弹窗控制
        private bool showSettingsPopup = false;
        private Vector2 settingsScrollPosition;

        /// <summary>
        /// 绘制图集设置按钮和摘要
        /// </summary>
        private void DrawAtlasSettingsSection()
        {
            EditorGUILayout.BeginHorizontal();
            {
                // 禁用按钮当弹窗显示时
                GUI.enabled = !showSettingsPopup;
                if (GUILayout.Button(“图集设置”, GUILayout.Height(30)))
                {
                    showSettingsPopup = true;
                }
                GUI.enabled = true;

                GUILayout.FlexibleSpace();

                // 显示当前设置摘要
                EditorGUILayout.HelpBox(GetSettingsSummary(), MessageType.Info);
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
        }

        /// <summary>
        /// 绘制设置弹窗
        /// </summary>
        private void DrawSettingsPopup()
        {
            // 弹窗位置和大小
            float popupWidth = 450f;
            float popupHeight = 400f;
            float popupX = (position.width – popupWidth) / 2;
            float popupY = (position.height – popupHeight) / 2;
            Rect popupRect = new Rect(popupX, popupY, popupWidth, popupHeight);

            // 弹窗背景
            GUIStyle popupStyle = new GUIStyle(EditorStyles.helpBox);
            popupStyle.normal.background = MakeTex(2, 2, GetWindowBackgroundColor());

            // 开始弹窗区域
            GUILayout.BeginArea(popupRect, popupStyle);
            {
                // 弹窗标题栏
                GUILayout.BeginHorizontal(EditorStyles.toolbar);
                {
                    GUILayout.Label(“图集设置”, EditorStyles.boldLabel);
                    GUILayout.FlexibleSpace();

                    // 关闭按钮
                    if (GUILayout.Button(“✕”, EditorStyles.miniButton, GUILayout.Width(25)))
                    {
                        showSettingsPopup = false;
                    }
                }
                GUILayout.EndHorizontal();

                EditorGUILayout.Space();

                // 设置内容
                settingsScrollPosition = EditorGUILayout.BeginScrollView(settingsScrollPosition);
                {
                    // Padding 设置
                    EditorGUILayout.BeginHorizontal();
                    {
                        EditorGUILayout.LabelField(“Sprite间距 (Padding)”, GUILayout.Width(150));
                        padding = EditorGUILayout.IntSlider(padding, 0, 16);
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.Space();

                    // 布尔设置组
                    GUILayout.Label(“打包选项:”, EditorStyles.boldLabel);
                    trimAlpha = EditorGUILayout.ToggleLeft(“裁剪Alpha通道 (Trim Alpha)”, trimAlpha);
                    removeEmptySpace = EditorGUILayout.ToggleLeft(“移除空白空间”, removeEmptySpace);
                    useUnityPacker = EditorGUILayout.ToggleLeft(“使用Unity打包器”, useUnityPacker);
                    forceTrueColor = EditorGUILayout.ToggleLeft(“真彩色模式 (Truecolor)”, forceTrueColor);
                    forceARGB32 = EditorGUILayout.ToggleLeft(“强制ARGB32纹理格式”, forceARGB32);

                    EditorGUILayout.Space();

                    // 最大图集尺寸
                    GUILayout.Label(“最大图集尺寸:”, EditorStyles.boldLabel);
                    EditorGUILayout.BeginHorizontal();
                    {
                        DrawSizeButton(1024);
                        DrawSizeButton(2048);
                        DrawSizeButton(4096);
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.Space();

                    // 当前设置摘要
                    EditorGUILayout.HelpBox(GetDetailedSettingsSummary(), MessageType.Info);
                }
                EditorGUILayout.EndScrollView();

                EditorGUILayout.Space();

                // 按钮区域
                EditorGUILayout.BeginHorizontal();
                {
                    GUILayout.FlexibleSpace();

                    if (GUILayout.Button(“取消”, GUILayout.Width(80)))
                    {
                        showSettingsPopup = false;
                    }

                    if (GUILayout.Button(“确定”, GUILayout.Width(80)))
                    {
                        showSettingsPopup = false;
                        Debug.Log(“图集设置已更新: ” + GetDetailedSettingsSummary());
                    }
                }
                EditorGUILayout.EndHorizontal();
            }
            GUILayout.EndArea();

            // 优化:改进的点击外部检测
            HandlePopupOutsideClick(popupRect);
        }

        /// <summary>
        /// 处理弹窗外部点击 – 修复版本
        /// </summary>
        private void HandlePopupOutsideClick(Rect popupRect)
        {
            Event currentEvent = Event.current;

            // 只有在鼠标按下事件时才处理
            if (currentEvent.type == EventType.MouseDown)
            {
                Vector2 mousePosition = currentEvent.mousePosition;

                // 检查点击是否在弹窗外部
                bool isClickOutsidePopup = !popupRect.Contains(mousePosition);

                // 检查点击是否在主窗口内
                bool isClickInWindow = position.Contains(GUIUtility.GUIToScreenPoint(mousePosition));

                if (isClickOutsidePopup && isClickInWindow)
                {
                    showSettingsPopup = false;
                    currentEvent.Use();
                    Repaint();
                }
            }

            // ESC键关闭弹窗
            if (currentEvent.type == EventType.KeyDown && currentEvent.keyCode == KeyCode.Escape)
            {
                showSettingsPopup = false;
                currentEvent.Use();
                Repaint();
            }
        }

        /// <summary>
        /// 获取窗口背景颜色(适配深浅色主题)
        /// </summary>
        private Color GetWindowBackgroundColor()
        {
            return EditorGUIUtility.isProSkin ?
                new Color(0.22f, 0.22f, 0.22f) : // 深色主题
                new Color(0.76f, 0.76f, 0.76f);  // 浅色主题
        }

        private void DrawSizeButton(int size)
        {
            bool isSelected = (maxAtlasSize == size);
            GUIStyle buttonStyle = new GUIStyle(EditorStyles.miniButton);

            if (isSelected)
            {
                buttonStyle.normal.textColor = Color.green;
                buttonStyle.fontStyle = FontStyle.Bold;
            }

            if (GUILayout.Button($”{size}x{size}”, buttonStyle))
            {
                maxAtlasSize = size;
            }
        }

        /// <summary>
        /// 创建纯色纹理
        /// </summary>
        private Texture2D MakeTex(int width, int height, Color col)
        {
            Color[] pix = new Color[width * height];
            for (int i = 0; i < pix.Length; i++)
                pix[i] = col;
            Texture2D result = new Texture2D(width, height);
            result.SetPixels(pix);
            result.Apply();
            return result;
        }

        /// <summary>
        /// 获取详细设置摘要
        /// </summary>
        private string GetDetailedSettingsSummary()
        {
            return $”当前设置:
” +
                   $”• Sprite间距: {padding} 像素
” +
                   $”• 最大尺寸: {maxAtlasSize}x{maxAtlasSize}
” +
                   $”• 裁剪Alpha: {(trimAlpha ? “是” : “否”)}
” +
                   $”• 打包器: {(useUnityPacker ? “Unity” : “自定义”)}
” +
                   $”• 颜色模式: {(forceTrueColor ? “真彩色” : “压缩”)}
” +
                   $”• 纹理格式: {(forceARGB32 ? “ARGB32” : “默认”)}”;
        }

        /// <summary>
        /// 获取设置摘要
        /// </summary>
        private string GetSettingsSummary()
        {
            return $”Padding:{padding} Trim:{(trimAlpha ? “Y” : “N”)} ” +
                   $”Size:{maxAtlasSize} Packer:{(useUnityPacker ? “Unity” : “Custom”)}”;
        }

        /// <summary>
        /// 应用图集设置到NGUI
        /// </summary>
        private void ApplyAtlasSettings()
        {
            try
            {
                // 设置NGUI图集参数
                NGUISettings.atlasPadding = padding;
                NGUISettings.atlasTrimming = trimAlpha;
                //NGUISettings.atlasMaxSize = maxAtlasSize;
                NGUISettings.unityPacking = useUnityPacker;

                // 设置纹理格式相关
                if (forceTrueColor)
                {
                    // 强制真彩色设置
                    NGUISettings.keepPadding = true;
                }

                if (forceARGB32)
                {
                    // 强制ARGB32格式
                    NGUISettings.keepPadding = true;
                }

                Debug.Log($”✅ 应用图集设置: Padding={padding}, TrimAlpha={trimAlpha}, ” +
                         $”MaxSize={maxAtlasSize}, UnityPacker={useUnityPacker}”);
            }
            catch (Exception e)
            {
                Debug.LogError($”应用图集设置失败: {e.Message}”);
            }
        }
        #endregion 图集设置 end

        [MenuItem(“Tools/Atlas/自动图集处理器”)]
        public static void ShowWindow()
        {
            var window = GetWindow<AtlasAutoProcessor>(“自动图集处理器”);
            window.minSize = new Vector2(450, 600);
            window.RefreshAtlasFolders();
        }

        private void OnGUI()
        {
            // 关键修复:先绘制主窗口,确保图集区域可以正常操作
            DrawMainWindow();

            // 如果有弹窗显示,再绘制阻挡层和弹窗
            if (showSettingsPopup)
            {
                DrawModalOverlay();
                DrawSettingsPopup();
            }
        }

        /// <summary>
        /// 绘制模态阻挡层 – 优化版本
        /// </summary>
        private void DrawModalOverlay()
        {
            // 创建全屏半透明黑色阻挡层
            Color originalColor = GUI.color;
            GUI.color = new Color(0, 0, 0, 0.15f); // 更浅的透明度,让背景更清晰可见
            GUI.Box(new Rect(0, 0, position.width, position.height), “”);
            GUI.color = originalColor;
        }

        /// <summary>
        /// 绘制主窗口内容 – 修复版本,确保弹窗显示时图集区域仍可操作
        /// </summary>
        private void DrawMainWindow()
        {
            DrawHeader();
            DrawPaths();
            DrawAtlasSettingsSection();
            DrawFolderList();
            DrawControls();
            DrawStatus();
        }

        private void DrawHeader()
        {
            GUILayout.Label(“自动图集处理器 – 优化创建顺序”, EditorStyles.boldLabel);
            EditorGUILayout.Space();
        }

        private void DrawPaths()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            {
                DrawPathField(“源目录:”, sourcePath);
                DrawPathField(“临时目录:”, targetPath);
                DrawPathField(“输出目录:”, outputPath);
            }
            EditorGUILayout.EndVertical();
            EditorGUILayout.Space();
        }

        private void DrawPathField(string label, string path)
        {
            EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
            EditorGUILayout.SelectableLabel(path, EditorStyles.textField,
                GUILayout.Height(EditorGUIUtility.singleLineHeight));
            EditorGUILayout.Space();
        }

        private void DrawFolderList()
        {
            EditorGUILayout.BeginHorizontal();
            {
                if (GUILayout.Button(“刷新文件夹列表”, GUILayout.Width(120)))
                    RefreshAtlasFolders();

                GUILayout.FlexibleSpace();

                if (atlasFolders.Count > 0)
                {
                    if (GUILayout.Button(“全选”, GUILayout.Width(60)))
                        SelectAll(true);
                    if (GUILayout.Button(“全不选”, GUILayout.Width(60)))
                        SelectAll(false);
                }
            }
            EditorGUILayout.EndHorizontal();

            if (atlasFolders.Count > 0)
            {
                GUILayout.Label($”找到 {atlasFolders.Count} 个图集文件夹:”, EditorStyles.boldLabel);
                scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(250));

                for (int i = 0; i < atlasFolders.Count; i++)
                {
                    EditorGUILayout.BeginHorizontal();
                    selectedFolders[i] = EditorGUILayout.Toggle(selectedFolders[i], GUILayout.Width(20));
                    EditorGUILayout.LabelField(Path.GetFileName(atlasFolders[i]));
                    EditorGUILayout.EndHorizontal();
                }

                EditorGUILayout.EndScrollView();
            }
            else
            {
                EditorGUILayout.HelpBox(“未找到图集文件夹,请检查源目录路径”, MessageType.Info);
            }
        }

        private void DrawControls()
        {
            EditorGUILayout.Space();

            bool canProcess = currentState == ProcessState.Idle && GetSelectedCount() > 0;

            GUI.enabled = canProcess && !showSettingsPopup; // 修复:弹窗显示时禁用开始处理按钮
            if (GUILayout.Button(“开始处理选中图集”, GUILayout.Height(40)))
            {
                StartProcessing();
            }
            GUI.enabled = true;

            if (currentState != ProcessState.Idle)
            {
                EditorGUILayout.Space();
                GUI.enabled = !showSettingsPopup; // 修复:弹窗显示时禁用停止处理按钮
                if (GUILayout.Button(“停止处理”, GUILayout.Height(30)))
                    StopProcessing();
                GUI.enabled = true;
            }
        }

        private void DrawStatus()
        {
            EditorGUILayout.Space();
            EditorGUILayout.LabelField(“当前状态:”, GetStateDisplayText(), EditorStyles.boldLabel);

            if (currentState != ProcessState.Idle)
            {
                float progress = GetProgress();
                EditorGUILayout.Space();
                Rect progressRect = EditorGUILayout.GetControlRect();
                EditorGUI.ProgressBar(progressRect, progress, GetProgressText());
            }
        }

        private void Update()
        {
            if (currentState == ProcessState.Importing)
            {
                float elapsed = (float)EditorApplication.timeSinceStartup – importStartTime;
                if (elapsed >= ImportWaitTime)
                {
                    AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
                    currentState = ProcessState.CreatingPrefabAndMat; // 进入创建prefab和mat阶段
                }
                Repaint();
            }
            else if (currentState == ProcessState.CreatingPrefabAndMat)
            {
                CreatePrefabAndMaterialForCurrentFolder();
            }
            else if (currentState == ProcessState.CreatingAtlas)
            {
                CreateAtlasForCurrentFolder();
            }
        }

        #region 核心逻辑
        private void RefreshAtlasFolders()
        {
            atlasFolders.Clear();

            if (!Directory.Exists(sourcePath))
            {
                Debug.LogError($”源目录不存在: {sourcePath}”);
                return;
            }

            var directories = Directory.GetDirectories(sourcePath, “atlas_*”, SearchOption.TopDirectoryOnly)
                                     .OrderBy(dir => Path.GetFileName(dir))
                                     .ToArray();

            atlasFolders.AddRange(directories);
            selectedFolders = new bool[atlasFolders.Count];

            Debug.Log($”找到 {atlasFolders.Count} 个图集文件夹”);
        }

        private void StartProcessing()
        {
            // 如果弹窗显示,不开始处理
            if (showSettingsPopup)
            {
                Debug.LogWarning(“图集设置弹窗显示中,请先关闭弹窗再开始处理”);
                return;
            }

            processingQueue.Clear();

            for (int i = 0; i < atlasFolders.Count; i++)
            {
                if (selectedFolders[i])
                    processingQueue.Enqueue(atlasFolders[i]);
            }

            if (processingQueue.Count == 0)
            {
                EditorUtility.DisplayDialog(“提示”, “请至少选择一个图集文件夹”, “确定”);
                return;
            }

            totalFoldersToProcess = processingQueue.Count;
            processedFolders = 0;

            EnsureDirectories();
            currentState = ProcessState.Copying;

            Debug.Log($”开始处理 {processingQueue.Count} 个图集文件夹…”);
            Debug.Log($”使用设置: {GetSettingsSummary()}”);

            ProcessNextFolder();
        }

        private void StopProcessing()
        {
            // 如果弹窗显示,不停止处理
            if (showSettingsPopup)
            {
                return;
            }

            currentState = ProcessState.Idle;
            processingQueue.Clear();
            currentFolder = null;
            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();

            Debug.Log(“图集处理已停止”);
        }

        private void ProcessNextFolder()
        {
            if (processingQueue.Count == 0)
            {
                FinalizeProcessing();
                return;
            }

            currentFolder = processingQueue.Dequeue();
            currentState = ProcessState.Copying;

            string folderName = Path.GetFileName(currentFolder);
            Debug.Log($”=== 开始处理文件夹: {folderName} ===”);

            CopyCurrentFolder();
        }

        private void CopyCurrentFolder()
        {
            string folderName = Path.GetFileName(currentFolder);
            string targetFolder = Path.Combine(targetPath, folderName);

            EditorUtility.DisplayProgressBar(“复制文件”, $”正在复制 {folderName}”, GetProgress());

            Debug.Log($”复制源文件夹: {currentFolder}”);
            Debug.Log($”复制目标文件夹: {targetFolder}”);

            // 清理目标文件夹
            CleanTargetFolder(targetFolder);

            // 确保目标目录存在
            Directory.CreateDirectory(targetFolder);

            // 复制所有图片文件
            bool copySuccess = CopyImageFiles(currentFolder, targetFolder);
            if (!copySuccess)
            {
                Debug.LogError($”复制文件夹失败: {currentFolder}”);
                ProcessNextFolder();
                return;
            }

            // 开始等待导入
            currentState = ProcessState.Importing;
            importStartTime = (float)EditorApplication.timeSinceStartup;

            Debug.Log($”复制完成,等待资源导入…”);
        }

        /// <summary>
        /// 第一步:创建Prefab和Material
        /// </summary>
        private void CreatePrefabAndMaterialForCurrentFolder()
        {
            // 如果弹窗显示,暂停处理
            if (showSettingsPopup)
            {
                return;
            }

            string folderName = Path.GetFileName(currentFolder);
            EditorUtility.DisplayProgressBar(“创建Prefab和Material”, $”正在处理 {folderName}”, GetProgress());

            Debug.Log($”🔄 第一步:为 {folderName} 创建Prefab和Material”);

            // 创建输出目录
            CheckCreateOutputDir(folderName);

            // 创建图集数据
            var data = CreateAtlasBatchData(folderName);

            // 先创建Prefab和Material
            bool success = CreatePrefabAndMaterial(data);

            if (success)
            {
                Debug.Log($”✅ 第一步完成:Prefab和Material创建成功”);
                // 进入第二步:创建图集
                currentState = ProcessState.CreatingAtlas;
            }
            else
            {
                Debug.LogError($”❌ 第一步失败:Prefab和Material创建失败”);
                processedFolders++;
                ProcessNextFolder();
            }
        }

        /// <summary>
        /// 第二步:创建图集PNG
        /// </summary>
        private void CreateAtlasForCurrentFolder()
        {
            // 如果弹窗显示,暂停处理
            if (showSettingsPopup)
            {
                return;
            }

            string folderName = Path.GetFileName(currentFolder);
            EditorUtility.DisplayProgressBar(“创建图集”, $”正在处理 {folderName}”, GetProgress());

            Debug.Log($”🔄 第二步:为 {folderName} 创建图集PNG”);

            string targetFolder = Path.Combine(targetPath, folderName);
            if (!Directory.Exists(targetFolder))
            {
                Debug.LogError($”目标文件夹不存在: {targetFolder}”);
                processedFolders++;
                ProcessNextFolder();
                return;
            }

            // 创建图集数据
            var data = CreateAtlasBatchData(folderName);

            // 加载纹理文件
            var imageFiles = Directory.GetFiles(targetFolder, “*.*”, SearchOption.TopDirectoryOnly)
                                    .Where(IsImageFile)
                                    .ToArray();

            foreach (string file in imageFiles)
            {
                data.texFileInfoList.Add(new FileInfo(file));
            }

            // 应用图集设置
            ApplyAtlasSettings();

            // 创建图集PNG
            bool success = CreateAtlasPNG(data);

            if (success)
            {
                Debug.Log($”✅ 图集 {folderName} 创建成功”);
            }
            else
            {
                Debug.LogError($”❌ 图集 {folderName} 创建失败”);
            }

            processedFolders++;

            // 处理下一个文件夹
            ProcessNextFolder();
        }

        private void FinalizeProcessing()
        {
            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
            AssetDatabase.SaveAssets();

            currentState = ProcessState.Complete;

            EditorUtility.DisplayDialog(“完成”, “所有图集处理完成”, “确定”);
            Debug.Log(“🎉 所有图集处理完成!”);

            // 重置状态
            currentState = ProcessState.Idle;
        }
        #endregion

        #region 文件操作
        private void EnsureDirectories()
        {
            if (!Directory.Exists(outputPath))
                Directory.CreateDirectory(outputPath);
            if (!Directory.Exists(targetPath))
                Directory.CreateDirectory(targetPath);
        }

        private void CleanTargetFolder(string targetFolder)
        {
            if (Directory.Exists(targetFolder))
            {
                try
                {
                    Directory.Delete(targetFolder, true);
                }
                catch (Exception e)
                {
                    Debug.LogWarning($”删除文件夹失败: {e.Message}”);
                }
            }

            // 删除meta文件
            string metaFile = targetFolder + “.meta”;
            if (File.Exists(metaFile))
            {
                try
                {
                    File.Delete(metaFile);
                }
                catch (Exception e)
                {
                    Debug.LogWarning($”删除meta文件失败: {e.Message}”);
                }
            }
        }

        private bool CopyImageFiles(string sourceDir, string targetDir)
        {
            try
            {
                if (!Directory.Exists(sourceDir))
                {
                    Debug.LogError($”源目录不存在: {sourceDir}”);
                    return false;
                }

                // 获取所有图片文件
                string[] imageFiles = Directory.GetFiles(sourceDir, “*.*”, SearchOption.AllDirectories)
                                             .Where(IsImageFile)
                                             .ToArray();

                Debug.Log($”找到 {imageFiles.Length} 个图片文件需要复制”);

                foreach (string sourceFile in imageFiles)
                {
                    try
                    {
                        string fileName = Path.GetFileName(sourceFile);
                        string destFile = Path.Combine(targetDir, fileName);

                        File.Copy(sourceFile, destFile, true);
                        Debug.Log($”成功复制: {fileName}”);
                    }
                    catch (Exception fileEx)
                    {
                        Debug.LogError($”复制文件 {sourceFile} 失败: {fileEx.Message}”);
                        return false;
                    }
                }

                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($”复制目录失败: {e.Message}”);
                return false;
            }
        }

        private bool IsImageFile(string filePath)
        {
            string extension = Path.GetExtension(filePath).ToLower();
            return extension == “.png” || extension == “.jpg” || extension == “.jpeg” || extension == “.tga”;
        }

        private string ConvertToAssetPath(string fullPath)
        {
            fullPath = fullPath.Replace('\', '/');
            string assetsPath = Application.dataPath.Replace('\', '/');

            if (fullPath.StartsWith(assetsPath))
            {
                return “Assets” + fullPath.Substring(assetsPath.Length);
            }

            return fullPath;
        }
        #endregion

        #region 图集创建 – 优化后的两步流程
        /// <summary>
        /// 创建图集批处理数据
        /// </summary>
        private AtlasBatchData CreateAtlasBatchData(string folderName)
        {
            var data = new AtlasBatchData
            {
                atlasName = folderName,
                atlasPath = ConvertToAssetPath(Path.Combine(outputPath, $”{folderName}.prefab”)),
                matPath = ConvertToAssetPath(Path.Combine(outputPath, $”{folderName}.mat”)),
                texPath = (Path.Combine(outputPath, $”{folderName}.png”))
            };

            data.atlasPathRelationAssets = data.atlasPath.Replace(Application.dataPath, “Assets”);
            data.matPathRelationAssets = data.matPath.Replace(Application.dataPath, “Assets”);
            data.texPathRelationAssets = data.texPath.Replace(Application.dataPath, “Assets”);

            return data;
        }

        /// <summary>
        /// 第一步:只创建Prefab和Material
        /// </summary>
        private bool CreatePrefabAndMaterial(AtlasBatchData data)
        {
            try
            {
                Debug.Log($”创建Prefab: {data.atlasPathRelationAssets}”);
                Debug.Log($”创建Material: {data.matPathRelationAssets}”);

                // 创建材质
                Material mat = CreateOrLoadMaterial(data.matPathRelationAssets);
                if (mat == null)
                {
                    Debug.LogError(“创建材质失败”);
                    return false;
                }

                // 创建Prefab
                CreateAtlasPrefab(data, mat);

                Debug.Log($”✅ 第一步完成:Prefab和Material创建成功”);
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($”创建Prefab和Material失败: {e.Message}”);
                Debug.LogError($”堆栈跟踪: {e.StackTrace}”);
                return false;
            }
        }

        /// <summary>
        /// 第二步:创建图集PNG
        /// </summary>
        private bool CreateAtlasPNG(AtlasBatchData data)
        {
            try
            {
                // 加载现有的Prefab和Atlas
                GameObject go = AssetDatabase.LoadAssetAtPath(data.atlasPathRelationAssets, typeof(GameObject)) as GameObject;
                if (go == null)
                {
                    Debug.LogError($”无法加载图集Prefab: {data.atlasPathRelationAssets}”);
                    return false;
                }

                NGUISettings.atlas = go.GetComponent<UIAtlas>();
                if (NGUISettings.atlas == null)
                {
                    Debug.LogError($”Prefab中没有UIAtlas组件: {data.atlasPathRelationAssets}”);
                    return false;
                }

                Selection.activeObject = NGUISettings.atlas;

                // 加载纹理并创建图集
                if (data.texFileInfoList.Count > 0)
                {
                    List<Texture> textures = new List<Texture>();
                    foreach (FileInfo info in data.texFileInfoList)
                    {
                        string path = info.FullName.Replace(“\”, “/”).Replace(Application.dataPath, “Assets”);
                        Texture tex = AssetDatabase.LoadAssetAtPath(path, typeof(Texture)) as Texture;
                        if (tex != null)
                        {
                            textures.Add(tex);
                            Debug.Log($”✅ 加载纹理: {tex.name}”);
                        }
                        else
                        {
                            Debug.LogError($”❌ 无法加载纹理: {path}”);
                        }
                    }

                    if (textures.Count > 0)
                    {
                        Debug.Log($”开始打包 {textures.Count} 个纹理到图集…”);

                        // 使用NGUI图集创建方法
                        UIAtlasMaker.RemoveExtractSprite(textures);
                        UIAtlasMaker.SetAtlasReadable(true);
                        UIAtlasMaker.UpdateAtlas(textures, true, false);
                        UIAtlasMaker.SetAtlasReadable(false);

                        Debug.Log($”✅ 图集PNG创建成功: {data.atlasName}”);
                        return true;
                    }
                    else
                    {
                        Debug.LogError(“没有找到有效的纹理文件”);
                        return false;
                    }
                }
                else
                {
                    Debug.LogError(“没有纹理文件需要处理”);
                    return false;
                }
            }
            catch (Exception e)
            {
                Debug.LogError($”创建图集PNG失败: {e.Message}”);
                Debug.LogError($”堆栈跟踪: {e.StackTrace}”);
                return false;
            }
        }

        /// <summary>
        /// 图集批处理数据类
        /// </summary>
        public class AtlasBatchData
        {
            public string atlasName;
            public string atlasPath;
            public string matPath;
            public string texPath;
            public string atlasPathRelationAssets;
            public string matPathRelationAssets;
            public string texPathRelationAssets;
            public List<FileInfo> texFileInfoList = new List<FileInfo>();
        }

        private void CheckCreateOutputDir(string folderName)
        {
            bool isNeedRefresh = false;
            if (!Directory.Exists(outputPath))
            {
                Directory.CreateDirectory(outputPath);
                isNeedRefresh = true;
            }

            if (isNeedRefresh)
            {
                AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
            }
        }

        /// <summary>
        /// 创建图集Prefab
        /// </summary>
        private void CreateAtlasPrefab(AtlasBatchData data, Material mat)
        {
            try
            {
                NGUISettings.currentPath = Path.GetDirectoryName(data.atlasPathRelationAssets);

                // 尝试加载现有的Prefab
                GameObject existingGo = AssetDatabase.LoadAssetAtPath(data.atlasPathRelationAssets, typeof(GameObject)) as GameObject;

                UnityEngine.Object prefab;
                if (existingGo != null)
                {
                    prefab = existingGo;
                    Debug.Log($”使用现有Prefab: {data.atlasPathRelationAssets}”);
                }
                else
                {
                    prefab = PrefabUtility.CreateEmptyPrefab(data.atlasPathRelationAssets);
                    Debug.Log($”创建新Prefab: {data.atlasPathRelationAssets}”);
                }

                // 创建GameObject并添加UIAtlas组件
                GameObject atlasGO = new GameObject(data.atlasName);
                UIAtlas atlas = atlasGO.AddComponent<UIAtlas>();
                atlas.spriteMaterial = mat;

                // 更新Prefab
                PrefabUtility.ReplacePrefab(atlasGO, prefab);
                UnityEngine.Object.DestroyImmediate(atlasGO);

                // 刷新资源
                AssetDatabase.Refresh();
                AssetDatabase.SaveAssets();

                Debug.Log($”✅ Atlas Prefab创建成功: {data.atlasName}”);
            }
            catch (Exception e)
            {
                Debug.LogError($”创建Atlas Prefab失败: {e.Message}”);
                Debug.LogError($”堆栈跟踪: {e.StackTrace}”);
                throw;
            }
        }

        private Material CreateOrLoadMaterial(string matPathRelationAssets)
        {
            try
            {
                // 尝试加载现有材质
                Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPathRelationAssets);
                if (mat != null)
                {
                    Debug.Log($”加载现有材质: {matPathRelationAssets}”);
                    return mat;
                }

                // 创建新材质
                Shader shader = Shader.Find(NGUISettings.atlasPMA ? “Unlit/Premultiplied Colored” : “Unlit/Transparent Colored”);
                if (shader == null)
                {
                    Debug.LogError(“无法找到NGUI Shader,尝试使用默认Shader”);
                    shader = Shader.Find(“UI/Default”);
                }

                if (shader == null)
                {
                    Debug.LogError(“无法找到任何可用的Shader”);
                    return null;
                }

                Debug.Log($”使用Shader: {shader.name} 创建材质”);

                mat = new Material(shader);

                // 确保目录存在
                string directory = Path.GetDirectoryName(matPathRelationAssets);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                AssetDatabase.CreateAsset(mat, matPathRelationAssets);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();

                Debug.Log($”材质创建成功: {matPathRelationAssets}”);

                // 重新加载材质
                mat = AssetDatabase.LoadAssetAtPath<Material>(matPathRelationAssets);
                return mat;
            }
            catch (Exception e)
            {
                Debug.LogError($”创建材质失败: {e.Message}”);
                Debug.LogError($”堆栈跟踪: {e.StackTrace}”);
                return null;
            }
        }
        #endregion

        #region 辅助方法
        private void SelectAll(bool selected)
        {
            if (selectedFolders == null) return;
            for (int i = 0; i < selectedFolders.Length; i++)
                selectedFolders[i] = selected;
        }

        private int GetSelectedCount()
        {
            return selectedFolders?.Count(x => x) ?? 0;
        }

        private string GetStateDisplayText()
        {
            return currentState switch
            {
                ProcessState.Idle => “就绪”,
                ProcessState.Copying => $”复制文件 – {Path.GetFileName(currentFolder)}”,
                ProcessState.Importing => $”等待导入 – {Path.GetFileName(currentFolder)}”,
                ProcessState.CreatingPrefabAndMat => $”创建Prefab和Material – {Path.GetFileName(currentFolder)}”,
                ProcessState.CreatingAtlas => $”创建图集PNG – {Path.GetFileName(currentFolder)}”,
                ProcessState.Complete => “处理完成”,
                _ => “未知状态”
            };
        }

        private string GetProgressText()
        {
            return $”处理进度: {processedFolders}/{totalFoldersToProcess}”;
        }

        private float GetProgress()
        {
            if (totalFoldersToProcess == 0) return 0f;
            return (float)processedFolders / totalFoldersToProcess;
        }

        private void OnDestroy()
        {
            StopProcessing();
        }
        #endregion
    }
}

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...