using UnityEngine; using UnityEngine.UI; using TMPro; namespace Colosseum.UI { /// /// 체력/마나 바 UI 컴포넌트 /// Slider 또는 Image.Fill 방식 지원 /// public class StatBar : MonoBehaviour { [Header("References - Slider 방식")] [SerializeField] private Slider slider; [Header("References - Fill Image 방식")] [SerializeField] private Image fillImage; [Header("References - 텍스트")] [SerializeField] private TMP_Text valueText; [Header("Colors")] [SerializeField] private Color fullColor = Color.green; [SerializeField] private Color lowColor = Color.red; [SerializeField] private float lowThreshold = 0.3f; [SerializeField] private bool useColorTransition = true; [Header("Animation")] [SerializeField] private bool smoothTransition = true; [SerializeField] private float lerpSpeed = 5f; private float currentValue; private float maxValue; private float displayValue; /// /// 바 값 설정 /// public void SetValue(float current, float max) { currentValue = current; maxValue = max; if (!smoothTransition) { displayValue = currentValue; } // 항상 즉시 시각적 업데이트 수행 UpdateVisuals(); } private void Update() { if (smoothTransition && !Mathf.Approximately(displayValue, currentValue)) { displayValue = Mathf.Lerp(displayValue, currentValue, lerpSpeed * Time.deltaTime); if (Mathf.Abs(displayValue - currentValue) < 0.01f) displayValue = currentValue; UpdateVisuals(); } } private void UpdateVisuals() { if (maxValue <= 0f) { Debug.LogWarning($"[StatBar:{gameObject.name}] UpdateVisuals: maxValue is {maxValue}, skipping"); return; } float ratio = Mathf.Clamp01(displayValue / maxValue); // Slider 방식 if (slider != null) { slider.value = ratio; // Slider 내부 Fill 이미지 색상 변경 if (useColorTransition && slider.fillRect != null) { var fillImg = slider.fillRect.GetComponent(); if (fillImg != null) { fillImg.color = ratio <= lowThreshold ? lowColor : fullColor; } } } // Image.Fill 방식 else if (fillImage != null) { fillImage.fillAmount = ratio; if (useColorTransition) { fillImage.color = ratio <= lowThreshold ? lowColor : fullColor; } } // 텍스트 if (valueText != null) { valueText.text = $"{Mathf.CeilToInt(displayValue)} / {Mathf.CeilToInt(maxValue)}"; } } private void OnValidate() { if (slider == null) slider = GetComponentInChildren(); if (fillImage == null && slider == null) fillImage = GetComponentInChildren(); } } }