164 lines
5.5 KiB
C#
164 lines
5.5 KiB
C#
using System.Collections;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
/// <summary>
|
||
/// 数字持续递增滚动组件(计数器效果,无最终值,一直递增)
|
||
/// 挂在 Text / TextMeshProUGUI 所在物体上:
|
||
/// - 面板上可设置显示位数(digitCount)
|
||
/// - 基础值随机:第一位 2~9,其余位全部随机
|
||
/// - 每次增加 2000 的倍数:随机倍数 1~500 倍,倍数越大随机到的概率越小
|
||
/// - 满位后重新随机一个基础值继续递增
|
||
/// 同时支持 UnityEngine.UI.Text 和 TextMeshProUGUI,二选一,留空自动从自身/子物体查找。
|
||
/// </summary>
|
||
public class TextNumRander : MonoBehaviour
|
||
{
|
||
[Header("目标文本(二选一,留空自动从自身/子物体查找)")]
|
||
[SerializeField] private Text text;
|
||
[SerializeField] private TextMeshProUGUI tmpText;
|
||
|
||
[Header("配置")]
|
||
[Tooltip("显示位数(面板上设置几位数)")]
|
||
[SerializeField] private int digitCount = 6;
|
||
[Tooltip("递增跳变间隔(秒),越小递增越快")]
|
||
[SerializeField] private float jumpInterval = 0.05f;
|
||
[Tooltip("启用时自动开始递增")]
|
||
[SerializeField] private bool autoStart = true;
|
||
|
||
[Header("递增规则")]
|
||
[Tooltip("每次增加的基础量(按 2000 的倍数)")]
|
||
[SerializeField] private long baseStep = 2000;
|
||
[Tooltip("随机倍数的上限(1 ~ maxMultiplier,越大概率越小)")]
|
||
[SerializeField] private int maxMultiplier = 500;
|
||
|
||
// ---- 运行时 ----
|
||
private Coroutine rollCoroutine;
|
||
private bool isRolling;
|
||
private long currentValue;
|
||
|
||
/// <summary>当前数值</summary>
|
||
public long CurrentValue => currentValue;
|
||
|
||
private void Awake()
|
||
{
|
||
// 自动查找文本组件:自身优先,其次子物体
|
||
if (text == null) text = GetComponent<Text>();
|
||
if (text == null) text = GetComponentInChildren<Text>();
|
||
if (tmpText == null) tmpText = GetComponent<TextMeshProUGUI>();
|
||
if (tmpText == null) tmpText = GetComponentInChildren<TextMeshProUGUI>();
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
if (autoStart && !isRolling)
|
||
StartRolling();
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
Stop();
|
||
}
|
||
|
||
/// <summary>设置显示位数(运行时调用会立即生效)</summary>
|
||
public void SetDigitCount(int count)
|
||
{
|
||
digitCount = Mathf.Max(1, count);
|
||
if (isRolling)
|
||
RefreshText();
|
||
}
|
||
|
||
/// <summary>开始(或继续)递增滚动:先随机一个基础值(第一位 2~9,其余位随机)</summary>
|
||
public void StartRolling()
|
||
{
|
||
if (isRolling) return;
|
||
// 基础值随机:第一位 2~9,其余位全部随机
|
||
currentValue = RandomBaseValue();
|
||
RefreshText();
|
||
isRolling = true;
|
||
rollCoroutine = StartCoroutine(RollLoop());
|
||
}
|
||
|
||
/// <summary>停止递增滚动(保留当前显示值)</summary>
|
||
public void Stop()
|
||
{
|
||
if (rollCoroutine != null)
|
||
{
|
||
StopCoroutine(rollCoroutine);
|
||
rollCoroutine = null;
|
||
}
|
||
isRolling = false;
|
||
}
|
||
|
||
/// <summary>设置起始数值(立即显示,不影响递增状态;末三位强制归 000)</summary>
|
||
public void SetStartValue(long value)
|
||
{
|
||
// 与递增规则保持一致:末三位固定为 000
|
||
currentValue = Wrap(System.Math.Max(0L, value) / 1000L * 1000L);
|
||
RefreshText();
|
||
}
|
||
|
||
private IEnumerator RollLoop()
|
||
{
|
||
while (isRolling)
|
||
{
|
||
// 每次增加 2000 的倍数:随机倍数 1~500 倍
|
||
currentValue += baseStep * RandomMultiplier();
|
||
if (currentValue > MaxValue())
|
||
currentValue = RandomBaseValue(); // 满位回绕:重新随机一个基础值
|
||
RefreshText();
|
||
yield return new WaitForSeconds(jumpInterval);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基础值随机:第一位 2~9,中间位随机,最后三位固定 000
|
||
/// (递增量为 2000 的倍数,基础值末三位为 000 时,后续所有值末三位始终保持 000)
|
||
/// </summary>
|
||
private long RandomBaseValue()
|
||
{
|
||
// 位数不足 4 位时,最后三位全是 0 意味着整个数就是 0
|
||
if (digitCount <= 3)
|
||
return 0;
|
||
|
||
long val = Random.Range(2, 10); // 第一位 2~9
|
||
for (int i = 1; i < digitCount - 3; i++)
|
||
val = val * 10 + Random.Range(0, 10); // 中间位随机 0~9
|
||
return val * 1000; // 最后三位固定 000
|
||
}
|
||
|
||
/// <summary>
|
||
/// 随机倍数 1 ~ maxMultiplier,倍数越大随机到的概率越小。
|
||
/// 用 500^u(u∈[0,1))采样:概率密度 ∝ 1/倍数,小倍数高频、大倍数低频。
|
||
/// </summary>
|
||
private long RandomMultiplier()
|
||
{
|
||
int m = Mathf.Clamp((int)Mathf.Pow(maxMultiplier, Random.value), 1, maxMultiplier);
|
||
return m;
|
||
}
|
||
|
||
/// <summary>当前位数能表示的最大值(10^digitCount - 1)</summary>
|
||
private long MaxValue()
|
||
{
|
||
long max = 1;
|
||
for (int i = 0; i < digitCount; i++)
|
||
max *= 10;
|
||
return max - 1;
|
||
}
|
||
|
||
/// <summary>数值限制在位数范围内</summary>
|
||
private long Wrap(long value)
|
||
{
|
||
if (value < 0) value = 0;
|
||
return value % (MaxValue() + 1);
|
||
}
|
||
|
||
private void RefreshText()
|
||
{
|
||
if (text == null && tmpText == null) return;
|
||
string s = currentValue.ToString().PadLeft(digitCount, '0');
|
||
if (text != null) text.text = s;
|
||
if (tmpText != null) tmpText.text = s;
|
||
}
|
||
}
|