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;
|
}
|
}
|
|
}
|