## NumberRollAnimation
``` cs
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
namespace SlotGame
{
///
/// 数字滚动动画组件 - 用于显示数字增加的滚动效果
/// Number rolling animation component - for displaying number increment rolling effects
///
public class NumberRollAnimation : MonoBehaviour
{
[Header("目标组件 Target Components")]
[SerializeField] private Text uiText;
[Header("动画设置 Animation Settings")]
[SerializeField] private float rollDuration = 2f;
[SerializeField] private AnimationCurve rollCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
[SerializeField] private bool useRandomRolling = true;
[SerializeField] private float randomRollSpeed = 0.05f;
[Header("大数字优化 Large Number Optimization")]
[SerializeField] private bool enableLargeNumberMode = true;
[SerializeField] private long largeNumberThreshold = 1000000; // 100万以上算大数字
[SerializeField] private float largeNumberDurationMultiplier = 1.5f; // 大数字动画时长倍数
[SerializeField] private float ultraLargeNumberThreshold = 100000000; // 1亿以上算超大数字
[SerializeField] private float ultraLargeNumberDurationMultiplier = 2.0f; // 超大数字动画时长倍数
[SerializeField] private int largeNumberUpdateInterval = 2; // 大数字更新间隔帧数(优化性能)
[Header("数字格式 Number Format")]
[SerializeField] private string numberFormat = "N0"; // N0 = 1,234,567
[SerializeField] private bool useCustomFormat = false;
[SerializeField] private string customFormat = "{0:N0}";
[Header("滚动效果 Rolling Effects")]
[SerializeField] private bool enableSound = true;
[SerializeField] private AudioClip rollSound;
[SerializeField] private AudioClip completeSound;
[SerializeField] private bool enableShake = false;
[SerializeField] private float shakeIntensity = 2f;
[Header("调试 Debug")]
[SerializeField] private bool debugMode = false;
// 私有变量
private long currentValue;
private long targetValue;
private bool isRolling = false;
private Coroutine rollCoroutine;
private AudioSource audioSource;
private Vector3 originalPosition;
private int frameCounter = 0; // 用于大数字性能优化
// 事件
public event Action OnValueChanged;
public event Action OnRollComplete;
public event Action OnRollStart;
#region Unity生命周期
private void Awake()
{
InitializeComponents();
}
private void Start()
{
originalPosition = transform.localPosition;
}
#endregion
#region 初始化
private void InitializeComponents()
{
// 自动获取文本组件
if (uiText == null) uiText = GetComponent();
// 获取或创建AudioSource
audioSource = GetComponent();
if (audioSource == null && enableSound)
{
audioSource = gameObject.AddComponent();
audioSource.playOnAwake = false;
}
}
#endregion
#region 公共方法
///
/// 设置当前值(无动画)
///
public void SetValue(long value)
{
currentValue = value;
targetValue = value;
UpdateDisplayText(value);
if (debugMode) Debug.Log($"NumberRoll: Set value to {value}");
}
///
/// 滚动到目标值
///
public void RollToValue(long targetValue, float? customDuration = null)
{
if (isRolling)
{
StopRoll();
}
this.targetValue = targetValue;
float duration = customDuration ?? CalculateOptimalDuration(currentValue, targetValue);
rollCoroutine = StartCoroutine(RollCoroutine(currentValue, targetValue, duration));
if (debugMode) Debug.Log($"NumberRoll: Rolling from {currentValue} to {targetValue} in {duration}s");
}
///
/// 增加值(从当前值滚动增加)
///
public void AddValue(long addAmount, float? customDuration = null)
{
long newTarget = currentValue + addAmount;
RollToValue(newTarget, customDuration);
}
///
/// 停止滚动
///
public void StopRoll()
{
if (rollCoroutine != null)
{
StopCoroutine(rollCoroutine);
rollCoroutine = null;
}
isRolling = false;
currentValue = targetValue;
UpdateDisplayText(currentValue);
// 重置位置
if (enableShake)
{
transform.localPosition = originalPosition;
}
}
///
/// 立即完成滚动
///
public void CompleteRoll()
{
StopRoll();
OnRollComplete?.Invoke(currentValue);
}
#endregion
#region 大数字优化方法
///
/// 根据数字大小计算最佳动画时长
///
private float CalculateOptimalDuration(long startValue, long endValue)
{
if (!enableLargeNumberMode)
return rollDuration;
long difference = Math.Abs(endValue - startValue);
if (difference >= ultraLargeNumberThreshold)
{
// 超大数字:1亿以上
return rollDuration * ultraLargeNumberDurationMultiplier;
}
else if (difference >= largeNumberThreshold)
{
// 大数字:100万以上
return rollDuration * largeNumberDurationMultiplier;
}
else
{
// 普通数字
return rollDuration;
}
}
///
/// 检查是否为大数字
///
private bool IsLargeNumber(long value)
{
return enableLargeNumberMode && Math.Abs(value) >= largeNumberThreshold;
}
///
/// 检查是否需要跳帧优化(大数字性能优化)
///
private bool ShouldSkipFrame()
{
if (!IsLargeNumber(targetValue))
return false;
frameCounter++;
if (frameCounter >= largeNumberUpdateInterval)
{
frameCounter = 0;
return false;
}
return true;
}
#endregion
#region 滚动逻辑
private IEnumerator RollCoroutine(long startValue, long endValue, float duration)
{
isRolling = true;
frameCounter = 0;
OnRollStart?.Invoke();
// 播放滚动音效
if (enableSound && rollSound != null && audioSource != null)
{
audioSource.clip = rollSound;
audioSource.loop = true;
audioSource.Play();
}
float elapsedTime = 0f;
long difference = endValue - startValue;
bool isLargeNum = IsLargeNumber(endValue);
// 大数字使用不同的随机策略
float randomIntensity = isLargeNum ? 0.05f : 0.1f; // 大数字减少随机波动
float randomPhase = isLargeNum ? 0.9f : 0.8f; // 大数字延长随机阶段
if (debugMode && isLargeNum)
Debug.Log($"NumberRoll: Large number detected, using optimized animation for {endValue}");
while (elapsedTime < duration)
{
elapsedTime += Time.deltaTime;
float progress = elapsedTime / duration;
float curveProgress = rollCurve.Evaluate(progress);
// 计算当前值
long rollingValue;
if (useRandomRolling && progress < randomPhase)
{
rollingValue = startValue + (long)(difference * curveProgress);
// 大数字优化:减少随机波动强度,增加波动频率控制
if (Time.time % randomRollSpeed < Time.deltaTime)
{
long randomOffset = (long)(difference * randomIntensity * UnityEngine.Random.Range(-1f, 1f));
rollingValue += randomOffset;
}
}
else
{
rollingValue = startValue + (long)(difference * curveProgress);
}
currentValue = rollingValue;
// 大数字性能优化:跳帧更新
if (!ShouldSkipFrame())
{
UpdateDisplayText(currentValue);
OnValueChanged?.Invoke(currentValue);
}
// 震动效果
if (enableShake)
{
float shakeAmount = shakeIntensity * (1f - progress);
// 大数字减少震动强度
if (isLargeNum) shakeAmount *= 0.5f;
Vector3 shakeOffset = new Vector3(
UnityEngine.Random.Range(-shakeAmount, shakeAmount),
UnityEngine.Random.Range(-shakeAmount, shakeAmount),
0f
);
transform.localPosition = originalPosition + shakeOffset;
}
yield return null;
}
// 确保最终值正确
currentValue = endValue;
UpdateDisplayText(currentValue);
// 重置位置
if (enableShake)
{
transform.localPosition = originalPosition;
}
// 停止滚动音效,播放完成音效
if (enableSound && audioSource != null)
{
audioSource.Stop();
if (completeSound != null)
{
audioSource.PlayOneShot(completeSound);
}
}
isRolling = false;
rollCoroutine = null;
OnValueChanged?.Invoke(currentValue);
OnRollComplete?.Invoke(currentValue);
if (debugMode) Debug.Log($"NumberRoll: Completed rolling to {currentValue}");
}
#endregion
#region 文本更新
private void UpdateDisplayText(long value)
{
string formattedText = FormatNumber(value);
if (uiText != null)
uiText.text = formattedText;
}
private string FormatNumber(long value)
{
if (useCustomFormat)
{
return string.Format(customFormat, value);
}
else
{
return value.ToString(numberFormat);
}
}
#endregion
#region 属性访问器
public long CurrentValue => currentValue;
public long TargetValue => targetValue;
public bool IsRolling => isRolling;
public float RollDuration
{
get => rollDuration;
set => rollDuration = Mathf.Max(0.1f, value);
}
///
/// 获取当前是否为大数字模式
///
public bool IsInLargeNumberMode => IsLargeNumber(currentValue) || IsLargeNumber(targetValue);
#endregion
#region 调试方法
[ContextMenu("Test Roll +1000")]
private void TestRoll1000()
{
AddValue(1000);
}
[ContextMenu("Test Roll +10000")]
private void TestRoll10000()
{
AddValue(10000);
}
[ContextMenu("Test Set 1000000")]
private void TestSetMillion()
{
SetValue(1000000);
}
[ContextMenu("Test Large Number +10000000")]
private void TestLargeNumber()
{
AddValue(10000000); // 1千万
}
[ContextMenu("Test Ultra Large Number +100000000")]
private void TestUltraLargeNumber()
{
AddValue(100000000); // 1亿
}
[ContextMenu("Test Jackpot Size")]
private void TestJackpotSize()
{
RollToValue(999999999); // 接近10亿
}
#endregion
}
}
```
## NumberRollExample
``` cs
using UnityEngine;
using UnityEngine.UI;
namespace SlotGame
{
///
/// 数字滚动动画使用示例
/// Number roll animation usage examples
///
public class NumberRollExample : MonoBehaviour
{
[Header("数字滚动组件引用 Number Roll References")]
[SerializeField] private NumberRollAnimation scoreRoll;
[SerializeField] private NumberRollAnimation jackpotRoll;
[SerializeField] private NumberRollAnimation winAmountRoll;
[SerializeField] private NumberRollAnimation balanceRoll;
[Header("翻页数字组件引用 Flip Number References")]
[SerializeField] private FlipNumberDisplay megaJackpotFlip;
[SerializeField] private FlipNumberDisplay ultraWinFlip;
[Header("测试按钮 Test Buttons")]
[SerializeField] private Button addScoreBtn;
[SerializeField] private Button addJackpotBtn;
[SerializeField] private Button showWinBtn;
[SerializeField] private Button updateBalanceBtn;
[Header("大数字测试按钮 Large Number Test Buttons")]
[SerializeField] private Button largeWinBtn;
[SerializeField] private Button megaJackpotBtn;
[SerializeField] private Button ultraWinBtn;
[SerializeField] private Button resetAllBtn;
[Header("测试数值 Test Values")]
[SerializeField] private long scoreIncrement = 1000;
[SerializeField] private long jackpotIncrement = 50000;
[SerializeField] private long winAmount = 25000;
[SerializeField] private long balanceAmount = 100000;
[Header("大数字测试数值 Large Number Test Values")]
[SerializeField] private long largeWinAmount = 50000000; // 5千万
[SerializeField] private long megaJackpotAmount = 500000000; // 5亿
[SerializeField] private long ultraWinAmount = 999999999999; // 接近万亿
private void Start()
{
InitializeUI();
RegisterEvents();
}
private void OnDestroy()
{
UnregisterEvents();
}
#region 初始化
private void InitializeUI()
{
// 设置初始值
if (scoreRoll != null)
scoreRoll.SetValue(0);
if (jackpotRoll != null)
jackpotRoll.SetValue(3000000); // 初始奖池
if (winAmountRoll != null)
winAmountRoll.SetValue(0);
if (balanceRoll != null)
balanceRoll.SetValue(50000); // 初始余额
// 设置大数字显示初始值
if (megaJackpotFlip != null)
megaJackpotFlip.SetValue(1000000000); // 10亿起始奖池
if (ultraWinFlip != null)
ultraWinFlip.SetValue(0);
}
private void RegisterEvents()
{
// 按钮事件
if (addScoreBtn != null)
addScoreBtn.onClick.AddListener(OnAddScore);
if (addJackpotBtn != null)
addJackpotBtn.onClick.AddListener(OnAddJackpot);
if (showWinBtn != null)
showWinBtn.onClick.AddListener(OnShowWin);
if (updateBalanceBtn != null)
updateBalanceBtn.onClick.AddListener(OnUpdateBalance);
// 大数字测试按钮事件
if (largeWinBtn != null)
largeWinBtn.onClick.AddListener(OnLargeWin);
if (megaJackpotBtn != null)
megaJackpotBtn.onClick.AddListener(OnMegaJackpot);
if (ultraWinBtn != null)
ultraWinBtn.onClick.AddListener(OnUltraWin);
if (resetAllBtn != null)
resetAllBtn.onClick.AddListener(OnResetAll);
// 数字滚动事件
if (scoreRoll != null)
{
scoreRoll.OnRollStart += () => Debug.Log("Score rolling started");
scoreRoll.OnRollComplete += (value) => Debug.Log($"Score rolling completed: {value:N0}");
}
if (winAmountRoll != null)
{
winAmountRoll.OnRollComplete += OnWinRollComplete;
}
// 大数字组件事件
if (megaJackpotFlip != null)
{
megaJackpotFlip.OnLargeNumberDetected += (value) => Debug.Log($"Mega Jackpot: Large number detected! {value:N0}");
megaJackpotFlip.OnSpinComplete += (value) => Debug.Log($"Mega Jackpot spin completed: {value:N0}");
}
if (ultraWinFlip != null)
{
ultraWinFlip.OnLargeNumberDetected += (value) => Debug.Log($"Ultra Win: Large number detected! {value:N0}");
ultraWinFlip.OnSpinComplete += OnUltraWinComplete;
}
}
private void UnregisterEvents()
{
if (addScoreBtn != null)
addScoreBtn.onClick.RemoveListener(OnAddScore);
if (addJackpotBtn != null)
addJackpotBtn.onClick.RemoveListener(OnAddJackpot);
if (showWinBtn != null)
showWinBtn.onClick.RemoveListener(OnShowWin);
if (updateBalanceBtn != null)
updateBalanceBtn.onClick.RemoveListener(OnUpdateBalance);
// 移除大数字测试按钮事件
if (largeWinBtn != null)
largeWinBtn.onClick.RemoveListener(OnLargeWin);
if (megaJackpotBtn != null)
megaJackpotBtn.onClick.RemoveListener(OnMegaJackpot);
if (ultraWinBtn != null)
ultraWinBtn.onClick.RemoveListener(OnUltraWin);
if (resetAllBtn != null)
resetAllBtn.onClick.RemoveListener(OnResetAll);
}
#endregion
#region 按钮事件处理
private void OnAddScore()
{
if (scoreRoll != null)
{
scoreRoll.AddValue(scoreIncrement, 1.5f); // 1.5秒滚动时间
}
}
private void OnAddJackpot()
{
if (jackpotRoll != null)
{
jackpotRoll.AddValue(jackpotIncrement, 2f); // 2秒滚动时间
}
}
private void OnShowWin()
{
if (winAmountRoll != null)
{
// 先重置为0,然后滚动到中奖金额
winAmountRoll.SetValue(0);
winAmountRoll.RollToValue(winAmount, 3f); // 3秒展示中奖动画
}
}
private void OnUpdateBalance()
{
if (balanceRoll != null)
{
balanceRoll.RollToValue(balanceAmount, 1f);
}
}
#endregion
#region 大数字测试事件处理
private void OnLargeWin()
{
Debug.Log($"Testing Large Win: {largeWinAmount:N0}");
// 使用NumberRollAnimation显示大奖
if (winAmountRoll != null)
{
winAmountRoll.SetValue(0);
winAmountRoll.RollToValue(largeWinAmount); // 自动使用大数字优化
}
// 同时更新分数(演示大数字性能优化)
if (scoreRoll != null)
{
StartCoroutine(DelayedScoreUpdate(largeWinAmount, 4f));
}
}
private void OnMegaJackpot()
{
Debug.Log($"Testing Mega Jackpot: {megaJackpotAmount:N0}");
// 使用FlipNumberDisplay显示超级大奖
if (megaJackpotFlip != null)
{
megaJackpotFlip.SpinToValue(megaJackpotAmount); // 自动使用Level 2优化
}
// 同时播放特效提示
ShowMegaJackpotEffect();
}
private void OnUltraWin()
{
Debug.Log($"Testing Ultra Win: {ultraWinAmount:N0}");
// 使用FlipNumberDisplay显示终极大奖
if (ultraWinFlip != null)
{
ultraWinFlip.SetValue(0);
ultraWinFlip.SpinToValue(ultraWinAmount); // 自动使用Level 3优化
}
// 触发终极大奖序列
StartCoroutine(UltraWinSequence());
}
private void OnResetAll()
{
Debug.Log("Resetting all displays to initial values");
// 重置所有数字显示
if (scoreRoll != null) scoreRoll.SetValue(0);
if (jackpotRoll != null) jackpotRoll.SetValue(3000000);
if (winAmountRoll != null) winAmountRoll.SetValue(0);
if (balanceRoll != null) balanceRoll.SetValue(50000);
if (megaJackpotFlip != null) megaJackpotFlip.SetValue(1000000000);
if (ultraWinFlip != null) ultraWinFlip.SetValue(0);
}
#endregion
#region 大数字特效和序列
private void ShowMegaJackpotEffect()
{
// 可以在这里添加粒子特效、屏幕震动等
Debug.Log("🎉 MEGA JACKPOT EFFECT! 🎉");
// 演示颜色变化效果
if (megaJackpotFlip != null)
{
megaJackpotFlip.SetLargeNumberColorEffect(Color.white, Color.yellow);
}
}
private System.Collections.IEnumerator UltraWinSequence()
{
Debug.Log("🌟 ULTRA WIN SEQUENCE STARTED! 🌟");
// 等待翻页动画完成
yield return new WaitForSeconds(6f);
// 显示所有数字的庆祝动画
Debug.Log("💰 ULTRA WIN CELEBRATION! 💰");
// 更新所有相关数字
if (scoreRoll != null)
scoreRoll.AddValue(ultraWinAmount / 10); // 添加部分到分数
if (balanceRoll != null)
balanceRoll.AddValue(ultraWinAmount); // 添加到余额
}
private System.Collections.IEnumerator DelayedScoreUpdate(long amount, float delay)
{
yield return new WaitForSeconds(delay);
if (scoreRoll != null)
{
scoreRoll.AddValue(amount);
}
}
#endregion
#region 游戏逻辑示例
///
/// 模拟老虎机获胜时的数字动画序列
///
public void SimulateSlotWin(long winAmount)
{
// 1. 显示中奖金额
if (winAmountRoll != null)
{
winAmountRoll.SetValue(0);
winAmountRoll.RollToValue(winAmount, 2f);
}
// 2. 延迟后更新分数和余额
StartCoroutine(UpdateScoreAndBalanceCoroutine(winAmount));
}
private System.Collections.IEnumerator UpdateScoreAndBalanceCoroutine(long winAmount)
{
// 等待中奖金额动画完成
yield return new WaitForSeconds(2.5f);
// 同时更新分数和余额
if (scoreRoll != null)
scoreRoll.AddValue(winAmount, 1.5f);
if (balanceRoll != null)
balanceRoll.AddValue(winAmount, 1.5f);
}
///
/// 模拟奖池增长
///
public void SimulateJackpotGrowth()
{
if (jackpotRoll != null)
{
// 随机增加奖池金额
long randomIncrease = Random.Range(1000, 10000);
jackpotRoll.AddValue(randomIncrease, 0.5f);
}
}
///
/// 模拟大奖级别检测和处理
///
public void SimulateLargeWinDetection(long winAmount)
{
string winLevel = GetWinLevelDescription(winAmount);
Debug.Log($"Win detected: {winAmount:N0} - {winLevel}");
// 根据奖金大小选择不同的显示组件
if (winAmount >= 1000000000000) // 1亿以上用翻页显示
{
if (ultraWinFlip != null)
{
ultraWinFlip.SpinToValue(winAmount);
}
}
else if (winAmount >= 100000000000) // 1千万以上用翻页显示
{
if (megaJackpotFlip != null)
{
megaJackpotFlip.SpinToValue(winAmount);
}
}
else // 普通奖金用滚动显示
{
if (winAmountRoll != null)
{
winAmountRoll.RollToValue(winAmount);
}
}
}
private string GetWinLevelDescription(long amount)
{
if (amount >= 1000000000000) return "ULTIMATE JACKPOT! 💎";
if (amount >= 100000000000) return "MEGA JACKPOT! 🏆";
if (amount >= 10000000000) return "SUPER JACKPOT! 🎊";
if (amount >= 1000000000) return "BIG JACKPOT! 🎉";
if (amount >= 100000000) return "Large Win! 💰";
if (amount >= 10000000) return "Good Win! 🎯";
return "Small Win";
}
#endregion
#region 事件回调
private void OnWinRollComplete(long finalValue)
{
Debug.Log($"Win amount animation completed: {finalValue:N0}");
// 可以在这里触发其他效果,比如粒子特效、音效等
// Trigger other effects like particles, sounds, etc.
}
private void OnUltraWinComplete(long finalValue)
{
Debug.Log($"🌟 ULTRA WIN COMPLETED: {finalValue:N0} 🌟");
// 超级大奖完成后的特殊处理
ShowUltraWinCelebration();
}
private void ShowUltraWinCelebration()
{
// 这里可以触发最华丽的庆祝效果
Debug.Log("🎆🎆🎆 ULTIMATE CELEBRATION! 🎆🎆🎆");
}
#endregion
#region 公共接口
///
/// 设置分数
///
public void SetScore(long score)
{
if (scoreRoll != null)
scoreRoll.SetValue(score);
}
///
/// 增加分数
///
public void AddScore(long amount)
{
if (scoreRoll != null)
scoreRoll.AddValue(amount);
}
///
/// 设置余额
///
public void SetBalance(long balance)
{
if (balanceRoll != null)
balanceRoll.SetValue(balance);
}
///
/// 更新余额
///
public void UpdateBalance(long newBalance)
{
if (balanceRoll != null)
balanceRoll.RollToValue(newBalance);
}
///
/// 显示大奖动画
///
public void ShowJackpotWin(long jackpotAmount)
{
if (winAmountRoll != null)
{
winAmountRoll.SetValue(0);
winAmountRoll.RollToValue(jackpotAmount, 5f); // 大奖用更长时间
}
}
///
/// 测试所有大数字效果
///
public void TestAllLargeNumberEffects()
{
StartCoroutine(TestSequence());
}
private System.Collections.IEnumerator TestSequence()
{
Debug.Log("开始大数字测试序列...");
// 测试1: 大奖 (5千万)
OnLargeWin();
yield return new WaitForSeconds(6f);
// 测试2: 超级大奖 (5亿)
OnMegaJackpot();
yield return new WaitForSeconds(8f);
// 测试3: 终极大奖 (接近万亿)
OnUltraWin();
yield return new WaitForSeconds(10f);
Debug.Log("大数字测试序列完成!");
}
#endregion
#region 调试方法
[ContextMenu("Test Slot Win")]
private void TestSlotWin()
{
SimulateSlotWin(15000);
}
[ContextMenu("Test Jackpot Growth")]
private void TestJackpotGrowth()
{
SimulateJackpotGrowth();
}
[ContextMenu("Test Big Win")]
private void TestBigWin()
{
ShowJackpotWin(500000);
}
[ContextMenu("Test Large Win Detection")]
private void TestLargeWinDetection()
{
SimulateLargeWinDetection(50000000); // 5千万
}
[ContextMenu("Test All Large Number Effects")]
private void TestAllEffects()
{
TestAllLargeNumberEffects();
}
[ContextMenu("Demo Ultra Jackpot")]
private void DemoUltraJackpot()
{
SimulateLargeWinDetection(999999999999); // 接近万亿
}
#endregion
}
}
```