diff --git a/Assets/GameScripts/Editor/SpritePostprocessor.cs b/Assets/GameScripts/Editor/SpritePostprocessor.cs
new file mode 100644
index 00000000..189254f5
--- /dev/null
+++ b/Assets/GameScripts/Editor/SpritePostprocessor.cs
@@ -0,0 +1,489 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using UnityEditor;
+using UnityEditor.U2D;
+using UnityEngine;
+using UnityEngine.U2D;
+using Object = UnityEngine.Object;
+
+///
+/// 图集导入管线。
+///
+public class SpritePostprocessor : AssetPostprocessor
+{
+ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
+ {
+ foreach (var s in importedAssets)
+ {
+ EditorSpriteSaveInfo.OnImportSprite(s);
+ }
+
+ foreach (var s in deletedAssets)
+ {
+ EditorSpriteSaveInfo.OnDeleteSprite(s);
+ }
+
+ foreach (var s in movedFromAssetPaths)
+ {
+ EditorSpriteSaveInfo.OnDeleteSprite(s);
+ }
+
+ foreach (var s in movedAssets)
+ {
+ EditorSpriteSaveInfo.OnImportSprite(s);
+ }
+ }
+}
+
+public static class EditorSpriteSaveInfo
+{
+ private const string NormalAtlasDir = "Assets/Atlas";
+ private const string UISpritePath = "Assets/AssetRaw/UIRaw";
+ private const string UIAtlasPath = "Assets/AssetRaw/UIRaw/Atlas";
+ private const string UIRawPath = "Assets/AssetRaw/UIRaw/UIRaw";
+ private static List m_dirtyAtlasList = new List();
+ private static Dictionary> m_allASprites = new Dictionary>();
+ private static Dictionary m_uiAtlasMap = new Dictionary();
+ private static bool m_inited = false;
+ private static bool m_dirty = false;
+
+ public static void Init()
+ {
+ if (m_inited)
+ {
+ return;
+ }
+
+ EditorApplication.update += CheckDirty;
+ }
+
+ public static void CheckDirty()
+ {
+ if (m_dirty)
+ {
+ m_dirty = false;
+
+ AssetDatabase.Refresh();
+ float lastProgress = -1;
+ for (int i = 0; i < m_dirtyAtlasList.Count; i++)
+ {
+ string atlasName = m_dirtyAtlasList[i];
+ Debug.Log("更新图集 : " + atlasName);
+ var curProgress = (float)i / m_dirtyAtlasList.Count;
+ if (curProgress > lastProgress + 0.01f)
+ {
+ lastProgress = curProgress;
+ var progressText = $"当前进度:{i}/{m_dirtyAtlasList.Count} {atlasName}";
+ bool cancel = EditorUtility.DisplayCancelableProgressBar("刷新图集" + atlasName, progressText, curProgress);
+ if (cancel)
+ {
+ break;
+ }
+ }
+
+ bool isUI = atlasName.StartsWith("UIRaw");
+ SaveAtlas(atlasName, isUI);
+ }
+
+ EditorUtility.ClearProgressBar();
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ m_dirtyAtlasList.Clear();
+ }
+ }
+
+ public static void OnImportSprite(string assetPath)
+ {
+ if (!assetPath.StartsWith(UISpritePath))
+ {
+ return;
+ }
+
+ TextureImporter ti = AssetImporter.GetAtPath(assetPath) as TextureImporter;
+
+ if (ti != null)
+ {
+ var modify = false;
+
+ if (assetPath.StartsWith(UISpritePath))
+ {
+ if (ti.textureType != TextureImporterType.Sprite)
+ {
+ ti.textureType = TextureImporterType.Sprite;
+ modify = true;
+ }
+
+ if (!string.IsNullOrEmpty(ti.spritePackingTag))
+ {
+ ti.spritePackingTag = string.Empty;
+ modify = true;
+ }
+
+ var setting = new TextureImporterSettings();
+ ti.ReadTextureSettings(setting);
+ if (setting.spriteGenerateFallbackPhysicsShape)
+ {
+ setting.spriteGenerateFallbackPhysicsShape = false;
+ ti.SetTextureSettings(setting);
+ modify = true;
+ }
+
+ if (IsKeepRawImage(assetPath))
+ {
+ //调整android格式
+ var andPlatformSettings = ti.GetPlatformTextureSettings("Android");
+ if (!andPlatformSettings.overridden)
+ {
+ andPlatformSettings.overridden = true;
+ modify = true;
+ }
+
+ if (andPlatformSettings.format != TextureImporterFormat.ASTC_6x6)
+ {
+ andPlatformSettings.format = TextureImporterFormat.ASTC_6x6;
+ ti.SetPlatformTextureSettings(andPlatformSettings);
+ modify = true;
+ }
+
+ //调整ios格式
+ var iosPlatformSettings = ti.GetPlatformTextureSettings("iPhone");
+ if (!iosPlatformSettings.overridden)
+ {
+ iosPlatformSettings.overridden = true;
+ modify = true;
+ }
+
+ if (iosPlatformSettings.format != TextureImporterFormat.ASTC_5x5)
+ {
+ iosPlatformSettings.format = TextureImporterFormat.ASTC_5x5;
+ iosPlatformSettings.compressionQuality = 50;
+ ti.SetPlatformTextureSettings(iosPlatformSettings);
+ modify = true;
+ }
+ }
+ }
+
+ if (modify)
+ {
+ ti.SaveAndReimport();
+ }
+
+ if (ti.textureType == TextureImporterType.Sprite)
+ {
+ OnProcessSprite(assetPath);
+ }
+ }
+ }
+
+ ///
+ /// 是否保持散图(不打图集)
+ ///
+ ///
+ ///
+ public static bool IsKeepRawImage(string dirPath)
+ {
+ return dirPath.Contains("UIRaw/Raw/") || dirPath.Contains("UIRaw_Raw_");
+ }
+
+ public static string GetSpritePath(string assetPath)
+ {
+ string path = assetPath.Substring(0, assetPath.LastIndexOf("."));
+ path = path.Replace("Assets/AssetRaw/", "");
+ return path;
+ }
+
+ ///
+ /// 根据文件路径,返回图集名称
+ ///
+ ///
+ ///
+ public static string GetPackageTag(string fullName)
+ {
+ fullName = fullName.Replace("\\", "/");
+ int idx = fullName.LastIndexOf("UIRaw", StringComparison.Ordinal);
+ if (idx == -1)
+ {
+ return "";
+ }
+
+ if (IsKeepRawImage(fullName))
+ {
+ return "";
+ }
+
+ var atlasPath = fullName.Substring(idx);
+ string str = atlasPath;
+ str = str.Substring(0, str.LastIndexOf("/", StringComparison.Ordinal)).Replace("/", "_");
+
+ return str;
+ }
+
+ public static void OnProcessSprite(string assetPath)
+ {
+ if (!assetPath.StartsWith("Assets"))
+ {
+ return;
+ }
+
+ if (assetPath.StartsWith("Assets/UIRaw_Delete"))
+ {
+ return;
+ }
+
+ Init();
+
+ var spriteName = Path.GetFileNameWithoutExtension(assetPath);
+ var spritePath = GetSpritePath(assetPath);
+ if (!m_uiAtlasMap.TryGetValue(spriteName, out string oldAssetPath) || spritePath == oldAssetPath)
+ {
+ m_uiAtlasMap[spriteName] = spritePath;
+ m_dirty = true;
+ }
+ else
+ {
+ Debug.LogError($"有重名的图片:{spriteName}\n旧图集:{oldAssetPath}\n新图集:{spritePath} ");
+ m_uiAtlasMap[spriteName] = spritePath;
+ m_dirty = true;
+ }
+
+ string atlasName = GetPackageTag(assetPath);
+ if (string.IsNullOrEmpty(atlasName))
+ {
+ bool keepRaw = IsKeepRawImage(assetPath);
+ if (!keepRaw)
+ {
+ Debug.LogError($"empty packingTag of asset :{assetPath} !!!");
+ }
+
+ return;
+ }
+ else
+ {
+ List ret;
+ if (!m_allASprites.TryGetValue(atlasName, out ret))
+ {
+ ret = new List();
+ m_allASprites.Add(atlasName, ret);
+ }
+
+ if (!ret.Contains(assetPath))
+ {
+ ret.Add(assetPath);
+ m_dirty = true;
+ if (!m_dirtyAtlasList.Contains(atlasName))
+ {
+ m_dirtyAtlasList.Add(atlasName);
+ }
+ }
+ }
+ }
+
+ public static void OnDeleteSprite(string assetPath)
+ {
+ if (assetPath.StartsWith("Assets/UIRaw_Delete"))
+ {
+ return;
+ }
+
+ if (!assetPath.StartsWith(UISpritePath))
+ {
+ return;
+ }
+
+ Init();
+ string atlasName = GetPackageTag(assetPath);
+ if (!m_allASprites.TryGetValue(atlasName, out var ret))
+ {
+ return;
+ }
+
+ //改成文件名的匹配
+ if (!ret.Exists(s => Path.GetFileName(s) == Path.GetFileName(assetPath)))
+ {
+ return;
+ }
+
+ if (assetPath.StartsWith(UISpritePath))
+ {
+ var spriteName = Path.GetFileNameWithoutExtension(assetPath);
+ if (m_uiAtlasMap.ContainsKey(spriteName))
+ {
+ m_uiAtlasMap.Remove(spriteName);
+ m_dirty = true;
+ }
+ }
+
+ ret.Remove(assetPath);
+ m_dirty = true;
+ if (!m_dirtyAtlasList.Contains(atlasName))
+ {
+ m_dirtyAtlasList.Add(atlasName);
+ }
+ }
+
+ #region 更新图集
+
+ public static void SaveAtlas(string atlasName, bool isUI)
+ {
+ List