hch
35 分钟以前 9075b06333a3fdd802f5e4d72858fbfc9cec0da7
Main/Component/UI/Common/BossLifeBar.cs
@@ -1,4 +1,4 @@
//--------------------------------------------------------
//--------------------------------------------------------
//    [Author]:           第二世界
//    [  Date ]:           Monday, September 11, 2017
//--------------------------------------------------------
@@ -8,164 +8,165 @@
using System.Text;
namespace vnxbqy.UI
public class BossLifeBar : MonoBehaviour
{
    [SerializeField] Sprite[] m_LifeBarSprites;
    public class BossLifeBar : MonoBehaviour
    [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)
    {
        [SerializeField] Sprite[] m_LifeBarSprites;
        surplusSegments = -1;
        totalSegments = _lifeBarCount;
        [SerializeField] Image m_BossIcon;
        [SerializeField] Image m_BackGround;
        [SerializeField] Image m_MiddleGround;
        [SerializeField] Image m_PrefaceGround;
        // 使用精确值,不再人为减小
        float percentage = (_maxHp > 0) ? (float)_hp / (float)_maxHp : 0f;
        targetValue = currentBehaviourValue = percentage * totalSegments;
        [SerializeField] Slider m_SliderMiddleground;
        [SerializeField] Slider m_SliderForeground;
        // 使用统一的 GetSegmentDecimal,避免小数精度导致进度条为0
        var behaviourDecimalValue = GetSegmentDecimal(currentBehaviourValue);
        m_SliderForeground.value = m_SliderMiddleground.value = behaviourDecimalValue;
        [SerializeField] Text m_Surplus;
        [SerializeField] Image m_Realm;
        [SerializeField] Text m_BossName;
        [SerializeField] Text m_BossLevel;
        refValue = 0f;
        [SerializeField] float m_SmoothTime = 0.3f;
        public float smoothTime {
            get { return m_SmoothTime; }
        }
        // 立刻显示基准百分比(使用 percentage)
        m_SurplusPercent.text = (percentage * 100f).ToString("F2") + "%";
    }
        Pattern pattern = Pattern.Reduce;
        float targetValue = 0f;
        int totalSegments = 1;
        int surplusSegments = -1;
    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;
        float refValue = 0f;
        float timer = 0f;
        float behaviourStartValue = 0f;
        behaviourStartValue = currentBehaviourValue;
        targetValue = tempValue;
        float m_CurrentBehaviourValue = 0f;
        float currentBehaviourValue {
            get { return m_CurrentBehaviourValue; }
            set {
                m_CurrentBehaviourValue = value;
                UpdateSurplusSegments(currentBehaviourValue);
                var behaviourDecimalValue = m_CurrentBehaviourValue - (int)m_CurrentBehaviourValue;
                var trueDecimalValue = targetValue - (int)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 ? 0 : trueDecimalValue;
                        break;
                    case Pattern.None:
                        m_SliderMiddleground.value = behaviourDecimalValue;
                        m_SliderForeground.value = behaviourDecimalValue;
                        break;
                }
            }
        }
        timer = 0f;
        refValue = 0f;
        public void SetBaseInfo(int _npcId, ulong _hp, ulong _maxHp, int _level)
        // 立即更新百分比显示(直接使用 percentage)
        m_SurplusPercent.text = (percentage * 100f).ToString("F2") + "%";
    }
    private void LateUpdate()
    {
        if (Mathf.Abs(currentBehaviourValue - targetValue) > 0.00001f)
        {
            var npcConfig = NPCConfig.Get(_npcId);
            m_BossName.text = npcConfig.charName;
            m_BossLevel.text = _level.ToString();
            m_BossIcon.SetSprite(npcConfig.HeadPortrait);
            if (m_Realm != null)
            {
                if (npcConfig.Realm > 0 && RealmConfig.Has(npcConfig.Realm))
                {
                    m_Realm.SetActive(true);
                    var realmConfig = RealmConfig.Get(npcConfig.Realm);
                    m_Realm.SetSprite(realmConfig.Img);
                }
                else
                {
                    m_Realm.SetActive(false);
                }
            }
            surplusSegments = -1;
            totalSegments = npcConfig.LifeBarCount;
            targetValue = currentBehaviourValue = ((float)_hp / _maxHp) * totalSegments - 0.0001f;
            var behaviourDecimalValue = currentBehaviourValue - (int)currentBehaviourValue;
            m_SliderForeground.value = m_SliderMiddleground.value = behaviourDecimalValue;
            refValue = 0f;
            var newValue = Mathf.SmoothDamp(currentBehaviourValue, targetValue, ref refValue, smoothTime);
            currentBehaviourValue = newValue;
        }
    }
        public void Show(ulong _hp, ulong _maxHp)
    static StringBuilder stringBuild = new StringBuilder();
    private void UpdateSurplusSegments(float _targetValue)
    {
        var currentSurplus = Mathf.CeilToInt(_targetValue);
        if (currentSurplus != surplusSegments)
        {
            var percentage = Mathf.Clamp(_hp, 0, _maxHp) / (float)_maxHp;
            var tempValue = totalSegments * percentage - 0.00001f;
            pattern = tempValue > targetValue ? Pattern.Add : tempValue < targetValue ? Pattern.Reduce : Pattern.None;
            surplusSegments = currentSurplus;
            var colorSetLength = m_LifeBarSprites.Length;
            var index = surplusSegments % colorSetLength;
            var nextIndex = index == 0 ? colorSetLength - 1 : index - 1;
            behaviourStartValue = currentBehaviourValue;
            targetValue = tempValue;
            m_PrefaceGround.overrideSprite = m_LifeBarSprites[index];
            m_MiddleGround.overrideSprite = m_LifeBarSprites[index];
            m_BackGround.overrideSprite = m_LifeBarSprites[nextIndex];
            timer = 0f;
            refValue = 0f;
            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") + "%";
        }
    }
        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);
                var chars = surplusSegments.ToString();
                stringBuild.Remove(0, stringBuild.Length);
                for (var i = 0; i < chars.Length; i++)
                {
                    var numChar = GetNumKey(chars[i]);
                    if (numChar > 0)
                    {
                        stringBuild.Append((char)numChar);
                    }
                }
                m_Surplus.text = stringBuild.ToString();
            }
        }
        int GetNumKey(int _num)
        {
            var config = DamageNumConfig.Get("BossLifeBarSurplusNum");
            return config.nums[_num - 48];
        }
    // int GetNumKey(int _num)
    // {
    //     var config = DamageNumConfig.Get("BossLifeBarSurplusNum");
    //     return config.nums[_num - 48];
    // }
        enum Pattern
        {
            None,
            Add,
            Reduce,
        }
    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);
    }
}