lcy
2 天以前 09bc892c7283df8757a07b646d5af21ddaa263d1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
using System;
using UnityEngine;
using UnityEngine.UI;
 
[DisallowMultipleComponent]
public class IntensifySmoothSlider : MonoBehaviour
{
    [SerializeField]
    Slider m_Slider;
    public Slider slider
    {
        get { return m_Slider; }
    }
 
    [SerializeField]
    [Range(0, 10)]
    float m_Delay = 0.2f;
    public float delay
    {
        get { return m_Delay; }
        set
        {
            m_Delay = Mathf.Clamp(value, 0, 10);
        }
    }
 
    [SerializeField]
    [Range(0, 1)]
    float m_Value = 0f;
    public float value
    {
        get
        {
            return m_Value;
        }
        set
        {
            m_Value = Mathf.Clamp01(value);
        }
    }
    
 
    // 值更新事件(ValueChangeAction)的触发分段数。
    // 用于降低 ValueChangeAction 的触发频率,防止UI文本等监听组件频繁刷新。
    // 
    // 工作原理:
    // 将滑块的 [0, 1] 范围划分为 'm_ValueUpdateSegments' 个数量相等的分段。
    // ValueChangeAction 事件仅在 slider.value 跨越这些分段边界时才会被触发。
    //
    // 示例:
    // - 设为 10: 则滑块值每变化 0.1 (10%) 触发一次事件 (如从 0.19 跨到 0.21 时)。
    // - 设为 100: 则滑块值每变化 0.01 (1%) 触发一次事件。
    [SerializeField]
    [Range(1, 1000)]
    int m_ValueUpdateSegments = 10; 
    public int ValueUpdateSegments
    {
        get { return m_ValueUpdateSegments; }
        set { m_ValueUpdateSegments = Mathf.Max(1, value); } // 至少为1
    }
 
    // 跟踪上一次触发事件时,滑块值所处的分段索引 (范围从 0 到 m_ValueUpdateSegments-1)。
    private int m_LastNotifiedSegment = -1;
 
 
    int m_Stage = 0;
    public int stage
    {
        get { return m_Stage; }
        set { m_Stage = value; }
    }
 
    private int presentStage;
    public int CurrentStage { get { return presentStage; } }
 
    float refSpeed = 0f;
    public event Action<int> StageUpAction;
    public event Action<float, int> ValueChangeAction;
    public event Action ChangeEndAction;
    public void ResetStage()
    {
        presentStage = stage;
    }
 
    public void ResetValue(float _value)
    {
        value = _value;
        if (slider != null)
        {
            slider.value = Mathf.Clamp01(_value);
        }
        // 重置值时,同步更新最后通知的分段索引
        m_LastNotifiedSegment = GetCurrentSegment(slider.value);
    }
 
    void OnEnable()
    {
        refSpeed = 0f;
        // 启用时,初始化最后通知的分段索引
        m_LastNotifiedSegment = GetCurrentSegment(slider != null ? slider.value : m_Value);
    }
 
    // 根据当前滑块值(0-1),计算其所属的分段索引(0 到 m_ValueUpdateSegments-1)
    private int GetCurrentSegment(float currentValue)
    {
        // 将 [0, 1] 范围的浮点数值 映射到 [0, m_ValueUpdateSegments-1] 范围的整数索引
        float preciseSegment = currentValue * m_ValueUpdateSegments;
        
        // 注意:当值为1.0f时,我们希望它落在最后一个分段索引上 (即 segments - 1)
        if (currentValue >= 1.0f)
        {
            return m_ValueUpdateSegments - 1;
        }
        return Mathf.FloorToInt(preciseSegment);
    }
 
 
    // 用于跟踪滑块是否正在缓动
    private bool isMoving = false;
 
    void LateUpdate()
    {
        if (slider == null)
        {
            return;
        }
 
        if (presentStage < m_Stage)
        {
            slider.value = Mathf.SmoothDamp(slider.value, 1, ref refSpeed, delay / 2);
 
            if (slider.value >= 0.99f)
            {
                slider.value = 0f;
                presentStage++;
                StageUpAction?.Invoke(presentStage);
                m_LastNotifiedSegment = 0;// 当血条循环时,重置分段索引
            }
 
            isMoving = true;
            CheckForValueChangeNotification(slider.value);
        }
        else
        {
            if (Mathf.Abs(slider.value - value) > 0.001f)
            {
                slider.value = Mathf.SmoothDamp(slider.value, value, ref refSpeed, delay);
                isMoving = true; 
                CheckForValueChangeNotification(slider.value);
            }
            else
            {
                if (isMoving)
                {
                    // 确保值在停止时完全精确
                    if (slider.value != value)
                    {
                        slider.value = value;
                        ValueChangeAction?.Invoke(slider.value, CurrentStage);
                        m_LastNotifiedSegment = GetCurrentSegment(slider.value);
                    }
                    ChangeEndAction?.Invoke(); 
                    isMoving = false;  
                }
            }
        }
    }
 
    // 检查是否需要触发ValueChangeAction的逻辑
    private void CheckForValueChangeNotification(float currentSliderValue)
    {
        int currentSegment = GetCurrentSegment(currentSliderValue);
        
        // 如果当前的分段索引与上次触发事件时的索引不同,说明已跨越分段边界。
        if (currentSegment != m_LastNotifiedSegment)
        {
            ValueChangeAction?.Invoke(currentSliderValue, CurrentStage);
            // 更新“上次触发”的索引为当前索引,防止本分段内重复触发。
            m_LastNotifiedSegment = currentSegment; 
        }
    }
 
}