Files
5.24BuYu/Assets/MyGame/aa/UI/EfScripts/Text/TextNumRander.cs
T
2026-10-18 19:46:43 +08:00

164 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}