## 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 } } ```