/*=================================================
*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
}
}


