using System.Collections; using TMPro; using UnityEngine; using UnityEngine.UI; /// /// 数字持续递增滚动组件(计数器效果,无最终值,一直递增) /// 挂在 Text / TextMeshProUGUI 所在物体上: /// - 面板上可设置显示位数(digitCount) /// - 基础值随机:第一位 2~9,其余位全部随机 /// - 每次增加 2000 的倍数:随机倍数 1~500 倍,倍数越大随机到的概率越小 /// - 满位后重新随机一个基础值继续递增 /// 同时支持 UnityEngine.UI.Text 和 TextMeshProUGUI,二选一,留空自动从自身/子物体查找。 /// 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; /// 当前数值 public long CurrentValue => currentValue; private void Awake() { // 自动查找文本组件:自身优先,其次子物体 if (text == null) text = GetComponent(); if (text == null) text = GetComponentInChildren(); if (tmpText == null) tmpText = GetComponent(); if (tmpText == null) tmpText = GetComponentInChildren(); } private void OnEnable() { if (autoStart && !isRolling) StartRolling(); } private void OnDisable() { Stop(); } /// 设置显示位数(运行时调用会立即生效) public void SetDigitCount(int count) { digitCount = Mathf.Max(1, count); if (isRolling) RefreshText(); } /// 开始(或继续)递增滚动:先随机一个基础值(第一位 2~9,其余位随机) public void StartRolling() { if (isRolling) return; // 基础值随机:第一位 2~9,其余位全部随机 currentValue = RandomBaseValue(); RefreshText(); isRolling = true; rollCoroutine = StartCoroutine(RollLoop()); } /// 停止递增滚动(保留当前显示值) public void Stop() { if (rollCoroutine != null) { StopCoroutine(rollCoroutine); rollCoroutine = null; } isRolling = false; } /// 设置起始数值(立即显示,不影响递增状态;末三位强制归 000) 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); } } /// /// 基础值随机:第一位 2~9,中间位随机,最后三位固定 000 /// (递增量为 2000 的倍数,基础值末三位为 000 时,后续所有值末三位始终保持 000) /// 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 } /// /// 随机倍数 1 ~ maxMultiplier,倍数越大随机到的概率越小。 /// 用 500^u(u∈[0,1))采样:概率密度 ∝ 1/倍数,小倍数高频、大倍数低频。 /// private long RandomMultiplier() { int m = Mathf.Clamp((int)Mathf.Pow(maxMultiplier, Random.value), 1, maxMultiplier); return m; } /// 当前位数能表示的最大值(10^digitCount - 1) private long MaxValue() { long max = 1; for (int i = 0; i < digitCount; i++) max *= 10; return max - 1; } /// 数值限制在位数范围内 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; } }