using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; #if UNITY_EDITOR using UnityEditor; #endif namespace AibisDream.UI { public class SpriteProgressBar : MonoBehaviour { [Header("进度条设置")] [SerializeField] private int spriteRendererCount = 10; [SerializeField] private int maxValue = 100; [SerializeField] private int currentValue = 0; [Header("显示设置")] [SerializeField] private Sprite sprite; [SerializeField] private float spacing = 1f; [SerializeField] private Vector3 startPosition = Vector3.zero; [SerializeField] private bool horizontal = true; [Header("渲染层级设置")] [CustomSortingLayer] [SerializeField] private int sortingLayerID = 0; [SerializeField] private int sortingOrder = 0; private UnityEvent onValueChanged = new UnityEvent(); /// /// 进度条值变化事件 /// public UnityEvent OnValueChanged => onValueChanged; private readonly List _spriteRenderers = new List(); private bool _isInitialized = false; #if UNITY_EDITOR private bool _editorUpdateScheduled = false; #endif public int CurrentValue { get => currentValue; set { if (currentValue == value) return; // 允许超出范围,不进行限制 currentValue = value; UpdateProgress(); } } public int MaxValue { get => maxValue; set { if (maxValue == value) return; maxValue = Mathf.Max(1, value); // 不再自动限制 currentValue,允许超出范围 UpdateProgress(); } } /// /// 获取用于界面显示的值(限制在 [0, MaxValue] 范围内) /// public int DisplayValue => Mathf.Clamp(currentValue, 0, maxValue); public float SpriteCount => spriteRendererCount; /// /// 获取所有 SpriteRenderer 的只读列表 /// public IReadOnlyList SpriteRenderers => _spriteRenderers; private void Awake() { #if UNITY_EDITOR // 运行时启动时,清理编辑器模式下创建的子对象 if (Application.isPlaying) { ClearEditorCreatedChildren(); } #endif if (!_isInitialized) { Initialize(); } } private void Start() { if (!_isInitialized) { Initialize(); } UpdateProgress(); } private void Initialize() { if (sprite == null) { Debug.LogWarning($"[SpriteProgressBar] {gameObject.name}: Sprite 未设置,无法创建进度条"); return; } ClearSpriteRenderers(); CreateSpriteRenderers(); _isInitialized = true; } #if UNITY_EDITOR /// /// 清理编辑器模式下创建的子对象(仅在运行时调用) /// private void ClearEditorCreatedChildren() { // 清理所有子对象,避免编辑器模式下创建的对象与运行时对象冲突 while (transform.childCount > 0) { var child = transform.GetChild(0); if (Application.isPlaying) { Destroy(child.gameObject); } else { DestroyImmediate(child.gameObject); } } _spriteRenderers.Clear(); _isInitialized = false; } #endif private void CreateSpriteRenderers() { if (sprite == null) return; for (int i = 0; i < spriteRendererCount; i++) { GameObject spriteObj = new GameObject($"ProgressItem_{i + 1}"); spriteObj.transform.SetParent(transform); #if UNITY_EDITOR // 编辑器模式下创建的对象不保存到场景 if (!Application.isPlaying) { spriteObj.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; } #endif // 计算位置 Vector3 position = startPosition; if (horizontal) { position.x += i * spacing; } else { position.y += i * spacing; } spriteObj.transform.localPosition = position; SpriteRenderer sr = spriteObj.AddComponent(); sr.sprite = sprite; sr.sortingLayerID = sortingLayerID; sr.sortingOrder = sortingOrder; _spriteRenderers.Add(sr); } } private void ClearSpriteRenderers() { #if UNITY_EDITOR // 在编辑器中,需要特殊处理 if (!Application.isPlaying) { // 清理子对象 while (transform.childCount > 0) { DestroyImmediate(transform.GetChild(0).gameObject); } } else #endif { // 运行时清理 foreach (var sr in _spriteRenderers) { if (sr != null && sr.gameObject != null) { Destroy(sr.gameObject); } } // 同时清理可能残留的子对象 while (transform.childCount > 0) { var child = transform.GetChild(0); Destroy(child.gameObject); } } _spriteRenderers.Clear(); } private void UpdateProgress() { if (_spriteRenderers.Count == 0 || maxValue <= 0) return; // 使用限制后的值来计算界面显示(不影响实际存储的值) int displayValue = DisplayValue; // 计算应该显示的 SpriteRenderer 数量(向上取整) float normalizedValue = (float)displayValue / maxValue; int activeCount = Mathf.CeilToInt(normalizedValue * spriteRendererCount); activeCount = Mathf.Clamp(activeCount, 0, spriteRendererCount); // 更新显示状态和排序层级 for (int i = 0; i < _spriteRenderers.Count; i++) { if (_spriteRenderers[i] != null) { _spriteRenderers[i].gameObject.SetActive(i < activeCount); // 确保排序层级始终是最新的 _spriteRenderers[i].sortingLayerID = sortingLayerID; _spriteRenderers[i].sortingOrder = sortingOrder; } } // 触发值变化事件 onValueChanged?.Invoke(currentValue); } #if UNITY_EDITOR private void OnValidate() { // 确保值有效(但不限制 currentValue,允许超出范围) spriteRendererCount = Mathf.Max(1, spriteRendererCount); maxValue = Mathf.Max(1, maxValue); // currentValue 不再限制,允许超出 [0, maxValue] 范围 spacing = Mathf.Max(0, spacing); // 如果不在播放模式,在编辑器中预览 if (!Application.isPlaying) { // 如果 Sprite 已设置,在编辑器中预览 if (sprite != null) { // 延迟执行,避免在序列化过程中出现问题 if (!_editorUpdateScheduled) { _editorUpdateScheduled = true; EditorApplication.delayCall += OnEditorUpdate; } } else { // 如果没有 Sprite,清理现有的渲染器 if (_spriteRenderers.Count > 0) { ClearSpriteRenderers(); _isInitialized = false; } } } else { // 运行时如果排序层级改变,更新所有 SpriteRenderer if (_spriteRenderers.Count > 0) { UpdateSortingLayers(); } } } private void OnEditorUpdate() { _editorUpdateScheduled = false; if (this == null || gameObject == null) return; // 移除延迟调用 EditorApplication.delayCall -= OnEditorUpdate; if (!Application.isPlaying && sprite != null) { _isInitialized = false; Initialize(); UpdateProgress(); } } #endif private void UpdateSortingLayers() { foreach (var sr in _spriteRenderers) { if (sr != null) { sr.sortingLayerID = sortingLayerID; sr.sortingOrder = sortingOrder; } } } } }