refactor: 移除SpriteGroupKit并清理诊疗旧指令

Made-with: Cursor
This commit is contained in:
2026-02-28 15:55:29 +08:00
parent cf0a6696c8
commit 19c290091e
8 changed files with 4 additions and 674 deletions
@@ -1,195 +0,0 @@
using System.Linq;
using AibisDream.Framework;
using UnityEditor;
using UnityEngine;
namespace AibisDream.SystemEditor
{
[CustomEditor(typeof(SpriteGroupKit))]
public class SpriteGroupEditor : Editor
{
private int _stateIdx;
private string _curState;
public override void OnInspectorGUI()
{
// 获取对象
var example = (SpriteGroupKit)target;
// 先绘制默认的 Inspector
DrawDefaultInspector();
#region UI
LoadUIPart(example); // 加载
EditorGUILayout.Separator();
SwitchStateUIPart(example); // 状态管理
EditorGUILayout.Separator();
ReorderLayer(example); // 重排序
EditorGUILayout.Separator();
SaveUIPart(example); // 保存
#endregion
}
private void LoadUIPart(SpriteGroupKit example)
{
EditorGUILayout.LabelField("加载图片集", EditorKit.BoldFont);
example.config.key = EditorGUILayout.TextField("唯一索引", example.config.key);
example.spriteGroup =
EditorGUILayout.ObjectField("PSD文件", example.spriteGroup, typeof(GameObject), true) as GameObject;
#region
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("按PSD加载"))
{
if (example.spriteGroup)
{
var option = ShowWarningDialog();
if (option == 0)
{
example.InstantiateByPsd();
ReLoad();
}
}
else
{
Debug.Log("PSD没有设置");
}
}
if (GUILayout.Button("按索引加载"))
{
if (!string.IsNullOrEmpty(example.config.key))
{
var option = ShowWarningDialog();
if (option == 0)
{
example.InstantiateByConfig();
ReLoad();
}
}
else
{
Debug.Log("PSD没有设置");
}
}
EditorGUILayout.EndHorizontal();
#endregion
}
private void SwitchStateUIPart(SpriteGroupKit example)
{
EditorGUILayout.LabelField("状态切换", EditorKit.BoldFont);
EditorGUILayout.BeginHorizontal();
var stateArray = example.config.stateDict.Keys.ToArray();
var newIndex = EditorGUILayout.Popup(_stateIdx, stateArray);
_curState = EditorGUILayout.TextField(_curState);
if (newIndex != _stateIdx && newIndex >= 0 && newIndex < stateArray.Length)
{
_stateIdx = newIndex;
_curState = stateArray[newIndex];
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("保存为状态"))
{
OnSaveStateClick(example);
}
if (GUILayout.Button("加载状态"))
{
OnLoadStateClick(example);
}
EditorGUILayout.EndHorizontal();
}
private void OnSaveStateClick(SpriteGroupKit example)
{
if (!string.IsNullOrEmpty(_curState))
{
example.SaveState(_curState);
}
else
{
Debug.Log("状态名不能为空");
}
}
private void OnLoadStateClick(SpriteGroupKit example)
{
if (!string.IsNullOrEmpty(_curState) && example.config.stateDict.ContainsKey(_curState))
{
EditorKit.RecordObjectAndChildren(example.gameObject, "加载状态");
example.SwitchState(_curState);
EditorUtility.SetDirty(example);
}
else
{
Debug.Log("状态名不能为空");
}
}
private void ReorderLayer(SpriteGroupKit example)
{
EditorGUILayout.LabelField("显示层级", EditorKit.BoldFont);
example.config.layerId = EditorKit.SortingLayerField("目标层级", example.config.layerId);
EditorGUILayout.BeginHorizontal();
example.config.maxLayer = EditorGUILayout.IntField("max", example.config.maxLayer);
example.config.minLayer = EditorGUILayout.IntField("min", example.config.minLayer);
EditorGUILayout.EndHorizontal();
if (GUILayout.Button("重排序"))
{
EditorKit.RecordObjectAndChildren(example.gameObject, "重新排序");
example.Reorder();
EditorUtility.SetDirty(example);
}
}
private void SaveUIPart(SpriteGroupKit example)
{
EditorGUILayout.LabelField("保存图片集", EditorKit.BoldFont);
if (GUILayout.Button("保存"))
{
example.SaveSpriteGroup();
}
if (GUILayout.Button("刷新"))
{
Repaint();
}
}
private void ReLoad()
{
// 清空编辑器数据
_stateIdx = -1;
_curState = "";
}
private int ShowWarningDialog()
{
return EditorUtility.DisplayDialogComplex(
"Warning",
"点击后会清除当前的图集,请提前保存",
"OK",
"Cancel",
string.Empty
);
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6e4590d14c3384044ab1f9f6a615286f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -252,60 +252,6 @@ MonoBehaviour:
minWidth: 150
bubbleStyle: {fileID: 11400000, guid: 25654f7ad2ed25b4e90b9c93da50b9b9, type: 2}
pivotType: 6
--- !u!1 &1370369938018575987
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 208936720767673838}
- component: {fileID: 1879757483991260023}
m_Layer: 0
m_Name: "\u4EBA\u7269\uFF08\u65B0\uFF09"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &208936720767673838
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1370369938018575987}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7333995943917754426}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1879757483991260023
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1370369938018575987}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 146b2fdfd6d201b409f26225a774f295, type: 3}
m_Name:
m_EditorClassIdentifier:
config:
key: "\u77F3\u5934"
layerId: 1134468525
maxLayer: 200
minLayer: 100
spriteGroup: {fileID: 3259275819111110517, guid: ae7c98b4bbd159c40954e9a3564b5b7a, type: 3}
data:
configKey:
curState:
shown: 0
--- !u!1 &1706035870180351282
GameObject:
m_ObjectHideFlags: 0
@@ -1121,8 +1067,8 @@ MonoBehaviour:
m_ShadowVolumeIntensityEnabled: 0
m_ShadowVolumeIntensity: 0.75
m_LocalBounds:
m_Center: {x: 0.032449722, y: -0.06375003, z: 0}
m_Extent: {x: 14.11495, y: 5.5668497, z: 0}
m_Center: {x: 0.034150124, y: -0.056200027, z: 0}
m_Extent: {x: 14.11155, y: 5.5709, z: 0}
m_PointLightInnerAngle: 360
m_PointLightOuterAngle: 360
m_PointLightInnerRadius: 0
@@ -1203,7 +1149,6 @@ Transform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 208936720767673838}
- {fileID: 8988582123737961170}
- {fileID: 1289813725535206033}
- {fileID: 8348444316318293934}
@@ -1224,7 +1169,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ee95229f127bf4c45ab49816cd2ea8c8, type: 3}
m_Name:
m_EditorClassIdentifier:
characterGroup: {fileID: 0}
bubbleSlotGroup: {fileID: 0}
--- !u!1 &5756145678206075836
GameObject:
@@ -1,4 +1,4 @@
using System.Collections;
using System.Collections;
using AibisDream.FixSystem;
using AibisDream.Framework;
using AibisDream.UI;
@@ -9,7 +9,6 @@ namespace AibisDream
{
public class ClinicSystem : MonoBehaviour
{
[HideInInspector] public SpriteGroupKit characterGroup;
private GameObject _coolingScreen;
[HideInInspector] public BubbleSlotGroup bubbleSlotGroup;
@@ -19,8 +18,6 @@ namespace AibisDream
FixSystemCenter.SystemDic.Register(this);
bubbleSlotGroup = transform.Find("Bubble Slot Group").GetComponent<BubbleSlotGroup>();
characterGroup = transform.GetComponentInChildren<SpriteGroupKit>();
// 注册Camera
var clinicCam = transform.Find("Clinic Camera").GetComponent<ICinemachineCamera>();
var coolingCam = transform.Find("Cooling Camera").GetComponent<ICinemachineCamera>();
@@ -16,37 +16,6 @@ namespace AibisDream
return ClinicSystem.Quit(duration);
}
[YarnCommand("init_character")]
public static IEnumerator InitCharacter(string key, string defaultState = "默认")
{
// 初始化
ClinicSystem.characterGroup.config.key = key;
ClinicSystem.characterGroup.gameObject.SetActive(false);
yield return ClinicSystem.characterGroup.InstantiateByConfigAsync();
// 加载初始表情
ClinicSystem.characterGroup.SwitchState(defaultState);
ClinicSystem.characterGroup.gameObject.SetActive(true);
}
[YarnCommand("switch_character_state")]
public static void SwitchCharacterState(string stateName)
{
ClinicSystem.characterGroup.SwitchState(stateName);
}
[YarnCommand("hide_character")]
public static IEnumerator HideCharacter(float duration = 1f)
{
return ClinicSystem.characterGroup.Fade(false, duration);
}
[YarnCommand("show_character")]
public static IEnumerator ShowCharacter(float duration = 1f)
{
return ClinicSystem.characterGroup.Fade(true, duration);
}
#region
[YarnCommand("character_init_new")]
+1 -31
View File
@@ -1,8 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AibisDream.Framework;
using AibisDream.Utility;
#if UNITY_EDITOR
using UnityEditor;
@@ -14,10 +13,8 @@ namespace AibisDream.Kit
public class ConfigUtil : SingletonBase<ConfigUtil>
{
private const string CharacterConfigPath = "/Config/character.csv";
private const string SpriteGroupPath = "/Config/sprite_group.json";
private Dictionary<string, Character> _characters;
private Dictionary<string, SpriteGroupConfig> _spriteConfigDict;
/// <summary>
/// 用于单例模式
@@ -42,7 +39,6 @@ namespace AibisDream.Kit
public override void OnSingletonInit()
{
InitCharacterConfig();
InitSpriteGroupConfig();
}
private void InitCharacterConfig()
@@ -51,11 +47,6 @@ namespace AibisDream.Kit
_characters = characterList.ToDictionary(item => item.Key, item => item);
}
private void InitSpriteGroupConfig()
{
_spriteConfigDict =
JsonUtil.ReadBeanDict<SpriteGroupConfig>(Application.streamingAssetsPath + SpriteGroupPath) ?? new Dictionary<string, SpriteGroupConfig>();
}
/// <summary>
/// 按key获取角色预设
@@ -68,27 +59,6 @@ namespace AibisDream.Kit
return _characters.TryGetValue(key, out character);
}
/// <summary>
/// 保存SpriteGroupConfig
/// </summary>
/// <param name="config"></param>
public void SaveSpriteGroupConfig(SpriteGroupConfig config)
{
_spriteConfigDict[config.key] = config;
SaveConfig(_spriteConfigDict, Application.streamingAssetsPath + SpriteGroupPath);
}
/// <summary>
/// 尝试获取Config
/// </summary>
/// <param name="key"></param>
/// <param name="config"></param>
/// <returns></returns>
public bool TryGetSpriteConfig(string key, out SpriteGroupConfig config)
{
return _spriteConfigDict.TryGetValue(key, out config);
}
/// <summary>
/// 按类型读取Json配置
/// </summary>
@@ -1,333 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Kit;
using AibisDream.Utility;
using DG.Tweening;
using Newtonsoft.Json;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace AibisDream.Framework
{
public class SpriteGroupKit : MonoBehaviour
{
#region
private Dictionary<string, SpriteRenderer> _rendererDict = new();
[HideInInspector] public SpriteGroupConfig config = new();
[HideInInspector] public GameObject spriteGroup;
private float _alpha;
#endregion
public event Action<SpriteGroupData> ChangeEvent;
public SpriteGroupData data;
private Dictionary<string, SpriteRenderer> RendererDict
{
get
{
if (_rendererDict is not { Count: > 0 })
{
if (transform.GetChild(0))
{
var rendererArray = transform.GetChild(0).GetComponentsInChildren<SpriteRenderer>(true);
_rendererDict = new Dictionary<string, SpriteRenderer>();
foreach (var rendererItem in rendererArray)
{
_rendererDict[rendererItem.gameObject.name] = rendererItem;
}
}
else
{
_rendererDict = new Dictionary<string, SpriteRenderer>();
}
}
return _rendererDict;
}
}
/// <summary>
/// 根据PS文件加载
/// </summary>
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<GameObject>(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;
}
if (Application.isPlaying)
{
data = new SpriteGroupData
{
configKey = config.key
};
ChangeEvent?.Invoke(data);
}
}
private void InstantiateGroup()
{
var root = Instantiate(spriteGroup, transform);
var rendererArray = root.GetComponentsInChildren<SpriteRenderer>(true);
_rendererDict = new Dictionary<string, SpriteRenderer>();
foreach (var rendererItem in rendererArray)
{
_rendererDict[rendererItem.gameObject.name] = rendererItem;
}
_alpha = 1;
}
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<GameObject>(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
/// <summary>
/// 切换状态
/// </summary>
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));
}
if (Application.isPlaying)
{
data.curState = stateName;
ChangeEvent?.Invoke(data);
}
}
public void SetActive(bool active)
{
if (transform.childCount <= 0) return;
transform.GetChild(0).gameObject.SetActive(active);
data.shown = active;
ChangeEvent?.Invoke(data);
}
public IEnumerator Fade(bool visible, float duration = 0.1f)
{
if (transform.childCount <= 0) yield break;
var endAlpha = visible ? 1 : 0;
yield return DOTween.To(() => _alpha, x => _alpha = x, endAlpha, duration)
.OnUpdate(() => SetAlpha(_alpha))
.WaitForCompletion();
data.shown = visible;
ChangeEvent?.Invoke(data);
}
private void SetAlpha(float alpha)
{
foreach (var rendererItem in _rendererDict.Values)
{
rendererItem.SetAlpha(alpha);
}
}
#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<string, string[]> 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<SpriteRenderer>
{
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);
}
}
[Serializable]
public struct SpriteGroupData
{
public string configKey;
public string curState;
public bool shown;
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 146b2fdfd6d201b409f26225a774f295
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: