using UnityEngine; using UnityEngine.UI; using TMPro; namespace AibisDream.UI { [ExecuteAlways] public class ProgressBar : MonoBehaviour { [SerializeField] float currentValue = 0f; [SerializeField] float maxValue = 100.0f; [SerializeField] bool hasText = true; [SerializeField] TextMeshProUGUI text; [SerializeField] RectTransform foreground; [SerializeField] RectTransform foregroundArea; [SerializeField] Vector2Int validRange = new Vector2Int(20, 80); [SerializeField] Color normalColor = Color.green; [SerializeField] Color abnormalColor = Color.red; [SerializeField] RectTransform rangeMarker; [SerializeField] Image foregroundImage; bool bDelayedUpdate = false; public float CurrentValue { get => currentValue; set { if(currentValue == value) { return; } currentValue = value; OnValueChanged(); } } public float MaxValue { get => maxValue; set { if(maxValue == value) { return; } maxValue = value; OnValueChanged(); } } public bool HasText { get => hasText; set { if (hasText == value) { return; } hasText = value; UpdateText(); } } public Vector2Int ValidRange { get => validRange; set { if (validRange == value) { return; } validRange = value; ValidateRange(); OnValueChanged(); } } void OnValueChanged() { if(maxValue < 0) { maxValue = 100.0f; } if(currentValue < 0) { currentValue = 0f; } currentValue = Mathf.Clamp(currentValue, 0, maxValue); UpdateGUI(); } void Start(){ UpdateGUI(); } void Update() { if(Application.isPlaying) { UpdateGUI(); } else { if(bDelayedUpdate) { bDelayedUpdate = false; OnValueChanged(); } } } void UpdateGUI() { UpdateForeground(); UpdateRangeMarker(); UpdateText(); } void UpdateForeground() { if (foreground == null || foregroundArea == null) { return; } float maxWidth = foregroundArea.rect.width; Vector2 offsetMax = foreground.offsetMax; offsetMax.x = -(maxWidth - maxWidth*(currentValue / maxValue)); foreground.offsetMax = offsetMax; // 根据范围检查结果设置颜色 if (foregroundImage != null) { foregroundImage.color = IsInRange(currentValue) ? normalColor : abnormalColor; } } void UpdateRangeMarker() { if (rangeMarker == null || foregroundArea == null || maxValue <= 0) { return; } float maxWidth = foregroundArea.rect.width; float rangeStart = validRange.x / maxValue * maxWidth; float rangeWidth = (validRange.y - validRange.x) / maxValue * maxWidth; // 设置范围标记的位置和大小 Vector2 offsetMin = rangeMarker.offsetMin; Vector2 offsetMax = rangeMarker.offsetMax; offsetMin.x = rangeStart; offsetMax.x = -(maxWidth - rangeStart - rangeWidth); rangeMarker.offsetMin = offsetMin; rangeMarker.offsetMax = offsetMax; } void UpdateText() { if (text != null && text.gameObject.activeSelf != hasText) { text.gameObject.SetActive(hasText); } if (hasText && (text != null)) { text.text = Mathf.Floor(currentValue) +"/"+ Mathf.Floor(maxValue); } } bool IsInRange(float value) { return value >= validRange.x && value <= validRange.y; } void ValidateRange() { if (validRange.x < 0) { validRange.x = 0; } if (validRange.y > maxValue) { validRange.y = Mathf.RoundToInt(maxValue); } if (validRange.x > validRange.y) { validRange.x = validRange.y; } } #if UNITY_EDITOR protected void OnValidate() { ValidateRange(); bDelayedUpdate = true; } #endif } }