//-------------------------------------------------------- // [Author]: 第二世界 // [ Date ]: Monday, September 11, 2017 //-------------------------------------------------------- using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Text; public class BossLifeBar : MonoBehaviour { [SerializeField] Sprite[] m_LifeBarSprites; [SerializeField] Image m_BackGround; [SerializeField] Image m_MiddleGround; [SerializeField] Image m_PrefaceGround; [SerializeField] Slider m_SliderMiddleground; [SerializeField] Slider m_SliderForeground; [SerializeField] Text m_Surplus; [SerializeField] Text m_SurplusPercent; [SerializeField] float m_SmoothTime = 0.3f; public float smoothTime { get { return m_SmoothTime; } } Pattern pattern = Pattern.Reduce; float targetValue = 0f; int totalSegments = 1; int surplusSegments = -1; float refValue = 0f; float timer = 0f; float behaviourStartValue = 0f; float m_CurrentBehaviourValue = 0f; float currentBehaviourValue { get { return m_CurrentBehaviourValue; } set { m_CurrentBehaviourValue = value; UpdateSurplusSegments(currentBehaviourValue); float behaviourDecimalValue = GetSegmentDecimal(m_CurrentBehaviourValue); float trueDecimalValue = GetSegmentDecimal(targetValue); switch (pattern) { case Pattern.Add: m_SliderForeground.value = behaviourDecimalValue; m_SliderMiddleground.value = behaviourDecimalValue > trueDecimalValue ? 1f : trueDecimalValue; break; case Pattern.Reduce: m_SliderMiddleground.value = behaviourDecimalValue; m_SliderForeground.value = behaviourDecimalValue < trueDecimalValue ? 0f : trueDecimalValue; break; case Pattern.None: m_SliderMiddleground.value = behaviourDecimalValue; m_SliderForeground.value = behaviourDecimalValue; break; } } } public void SetBaseInfo(int _lifeBarCount, ulong _hp, ulong _maxHp) { surplusSegments = -1; totalSegments = _lifeBarCount; // 使用精确值,不再人为减小 float percentage = (_maxHp > 0) ? (float)_hp / (float)_maxHp : 0f; targetValue = currentBehaviourValue = percentage * totalSegments; // 使用统一的 GetSegmentDecimal,避免小数精度导致进度条为0 var behaviourDecimalValue = GetSegmentDecimal(currentBehaviourValue); m_SliderForeground.value = m_SliderMiddleground.value = behaviourDecimalValue; refValue = 0f; // 立刻显示基准百分比(使用 percentage) m_SurplusPercent.text = (percentage * 100f).ToString("F2") + "%"; } public void Show(ulong _hp, ulong _maxHp) { var percentage = Mathf.Clamp(_hp, 0, _maxHp) / (float)_maxHp; var tempValue = totalSegments * percentage; // 不再减小 pattern = tempValue > targetValue ? Pattern.Add : tempValue < targetValue ? Pattern.Reduce : Pattern.None; behaviourStartValue = currentBehaviourValue; targetValue = tempValue; timer = 0f; refValue = 0f; // 立即更新百分比显示(直接使用 percentage) m_SurplusPercent.text = (percentage * 100f).ToString("F2") + "%"; } private void LateUpdate() { if (Mathf.Abs(currentBehaviourValue - targetValue) > 0.00001f) { var newValue = Mathf.SmoothDamp(currentBehaviourValue, targetValue, ref refValue, smoothTime); currentBehaviourValue = newValue; } } static StringBuilder stringBuild = new StringBuilder(); private void UpdateSurplusSegments(float _targetValue) { var currentSurplus = Mathf.CeilToInt(_targetValue); if (currentSurplus != surplusSegments) { surplusSegments = currentSurplus; var colorSetLength = m_LifeBarSprites.Length; var index = surplusSegments % colorSetLength; var nextIndex = index == 0 ? colorSetLength - 1 : index - 1; m_PrefaceGround.overrideSprite = m_LifeBarSprites[index]; m_MiddleGround.overrideSprite = m_LifeBarSprites[index]; m_BackGround.overrideSprite = m_LifeBarSprites[nextIndex]; m_BackGround.SetActive(surplusSegments > 1); m_Surplus.text = "x" + surplusSegments.ToString(); float pct = totalSegments > 0 ? Mathf.Clamp01(_targetValue / totalSegments) : 0f; // 修复格式并处理接近 100% 的情况 if (1f - pct < 0.00005f) pct = 1f; m_SurplusPercent.text = (pct * 100f).ToString("F2") + "%"; } } // int GetNumKey(int _num) // { // var config = DamageNumConfig.Get("BossLifeBarSurplusNum"); // return config.nums[_num - 48]; // } enum Pattern { None, Add, Reduce, } // helper: 返回段内小数部分;当恰好为整数且大于0时,返回1以表示满格(避免0导致进度条变空) private float GetSegmentDecimal(float value) { // 先判断是否为 0,避免被误判为"整段满格" if (value <= 0f) return 0f; // 使用一个小的容忍值来处理浮点误差,避免 near-integer 导致 0 const float eps = 1e-5f; // 先做一个向下稳定的 floor,避免 2.999999 变成 2 的问题 float stableFloor = Mathf.Floor(value + eps); float frac = value - stableFloor; // 只有在 value > 0 且接近整数时才返回 1(表示当前段满格) if (frac <= eps && value >= 1f - eps) return 1f; return Mathf.Clamp01(frac); } }