using System; using System.Collections; using System.Collections.Generic; using System.Linq; using AibisDream.Kit; using Newtonsoft.Json; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace AibisDream.Framework { public class SpriteGroupKit : MonoBehaviour { #region 索引 private Dictionary _rendererDict = new(); [HideInInspector] public SpriteGroupConfig config = new(); [HideInInspector] public GameObject spriteGroup; #endregion private Dictionary RendererDict { get { if (_rendererDict is not { Count: > 0 }) { if (transform.GetChild(0)) { var rendererArray = transform.GetChild(0).GetComponentsInChildren(true); _rendererDict = new Dictionary(); foreach (var rendererItem in rendererArray) { _rendererDict[rendererItem.gameObject.name] = rendererItem; } } else { _rendererDict = new Dictionary(); } } return _rendererDict; } } /// /// 根据PS文件加载 /// public void InstantiateByPsd() { if (spriteGroup) { // 先销毁 DestroyAllChildren(); // 再新建 InstantiateGroup(); // 把PSD名字填进去 // 加载配置文件,没有就空着 if (ConfigUtil.Instance.TryGetSpriteConfig(config.key, out var oldConfig)) { config = oldConfig; } else { config = new SpriteGroupConfig() { key = spriteGroup.name }; } } else { Debug.Log("请先设置要加载的图集"); } } public void InstantiateByConfig() { StartCoroutine(InstantiateByConfigAsync()); } public IEnumerator InstantiateByConfigAsync() { // 校验Key是否存在 if (!config.Validate()) yield break; // 查查有没有Prefab var request = Resources.LoadAsync(config.PrefabResourcePath); #if DEBUG if (request.asset == null) { Debug.Log($"prefab没有找到"); yield break; } #endif // 实例化Prefab spriteGroup = request.asset as GameObject; DestroyAllChildren(); InstantiateGroup(); // 加载配置文件,没有就空着 if (ConfigUtil.Instance.TryGetSpriteConfig(config.key, out var oldConfig)) { config = oldConfig; } } private void InstantiateGroup() { var root = Instantiate(spriteGroup, transform); var rendererArray = root.GetComponentsInChildren(true); _rendererDict = new Dictionary(); foreach (var rendererItem in rendererArray) { _rendererDict[rendererItem.gameObject.name] = rendererItem; } } private void DestroyAllChildren() { foreach (Transform child in transform) { #if UNITY_EDITOR if (!EditorApplication.isPlaying) { DestroyImmediate(child.gameObject); continue; } #endif Destroy(child.gameObject); } } #region 保存逻辑 public void SaveState(string curState) { var activeArray = RendererDict .Where(pair => pair.Value.gameObject.activeSelf) .Select(item => item.Key) .ToArray(); config.stateDict[curState] = activeArray; } public void SaveSpriteGroup() { // 先校验参数是不是都是正确的 if (!config.Validate()) { Debug.Log("配置项存在空字段"); return; } // 先保存Prefab SaveAsPrefab(transform.GetChild(0).gameObject, config.PrefabPath); // 再保存Config ConfigUtil.Instance.SaveSpriteGroupConfig(config); } private static void SaveAsPrefab(GameObject target, string localPath) { #if UNITY_EDITOR // 先验证Prefab是否存在 if (AssetDatabase.LoadAssetAtPath(localPath)) { // 如果存在,替换 Prefab PrefabUtility.SaveAsPrefabAssetAndConnect(target, localPath, InteractionMode.UserAction); Debug.Log("Prefab replaced at: " + localPath); } else { // 如果不存在,创建新的 Prefab PrefabUtility.SaveAsPrefabAsset(target, localPath); Debug.Log("Prefab created at: " + localPath); } #endif } #endregion #region 切换State /// /// 切换状态 /// public void SwitchState(string stateName) { // 检查是否存在 if (!config.stateDict.TryGetValue(stateName, out var activeArray)) return; // 按状态激活 foreach (var item in RendererDict.Values) { item.gameObject.SetActive(activeArray.Contains(item.gameObject.name)); } } #endregion #region 排序逻辑 public void Reorder() { if (!config.ValidateLayer()) { Debug.LogWarning("排序参数错误"); return; } if (RendererDict is not { Count: > 0 }) { Debug.LogWarning("还没有加载图集"); return; } // 排序 var renderers = RendererDict.Values; var sortedRenderers = renderers.OrderBy(item => item, new LayerComparer()).ToArray(); for (var i = 0; i < sortedRenderers.Length; i++) { sortedRenderers[i].sortingLayerID = config.layerId; sortedRenderers[i].sortingOrder = config.minLayer + i; } } #endregion } [Serializable] public class SpriteGroupConfig { [JsonIgnore] public string PrefabPath => $"Assets/Resources/SpriteGroup/{key}.prefab"; [JsonIgnore] public string PrefabResourcePath => $"SpriteGroup/{key}"; public string key; public int layerId; public int maxLayer; public int minLayer; public Dictionary stateDict = new(); public bool Validate() { return !string.IsNullOrEmpty(key); } public bool ValidateLayer() { if (!SortingLayer.IsValid(layerId)) return false; if (maxLayer <= minLayer) return false; return true; } } public class LayerComparer : IComparer { public int Compare(SpriteRenderer x, SpriteRenderer y) { if (ReferenceEquals(x, y)) return 0; if (ReferenceEquals(null, y)) return 1; if (ReferenceEquals(null, x)) return -1; var sortingLayerIDComparison = x.sortingLayerID.CompareTo(y.sortingLayerID); if (sortingLayerIDComparison != 0) return sortingLayerIDComparison; return x.sortingOrder.CompareTo(y.sortingOrder); } } }