## FlipNumberDisplay 翻页实现(未验证) ``` cs using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace SlotGame { /// /// 翻页数字显示器 - 模拟机械老虎机的数字滚轮效果 /// Flip number display - simulates mechanical slot machine number wheel effects /// [System.Serializable] public class DigitWheel { [Header("UI组件 UI Components")] public RectTransform wheelContainer; public List digitTexts = new List(); [Header("动画设置 Animation Settings")] public float spinSpeed = 1000f; public AnimationCurve spinCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); [HideInInspector] public int currentDigit = 0; [HideInInspector] public bool isSpinning = false; [HideInInspector] public Coroutine spinCoroutine; } public class FlipNumberDisplay : MonoBehaviour { [Header("数字轮设置 Digit Wheel Setup")] [SerializeField] private List digitWheels = new List(); [SerializeField] private int maxDigits = 12; // 增加到12位,支持千亿级别 [SerializeField] private float digitHeight = 60f; [Header("滚动设置 Spinning Settings")] [SerializeField] private float baseDuration = 2f; [SerializeField] private float extraDurationPerDigit = 0.3f; [SerializeField] private bool spinFromRightToLeft = true; [SerializeField] private float digitDelay = 0.1f; [Header("大数字优化 Large Number Optimization")] [SerializeField] private bool enableLargeNumberMode = true; [SerializeField] private long largeNumberThreshold = 10000000; // 1千万以上算大数字 [SerializeField] private float largeNumberSpeedMultiplier = 1.3f; // 大数字滚动速度倍数 [SerializeField] private int largeNumberMinSpins = 5; // 大数字最少转圈数 [SerializeField] private int largeNumberMaxSpins = 12; // 大数字最多转圈数 [SerializeField] private float largeNumberDelayReduction = 0.7f; // 大数字延迟减少倍数 [SerializeField] private bool enableSpectacularEffect = true; // 大数字华丽效果 [Header("音效设置 Sound Settings")] [SerializeField] private AudioClip spinSound; [SerializeField] private AudioClip stopSound; [SerializeField] private AudioClip largeNumberSound; // 大数字专用音效 [SerializeField] private AudioSource audioSource; [Header("调试 Debug")] [SerializeField] private bool debugMode = false; private long currentValue = 0; private long targetValue = 0; private bool isAnimating = false; // 事件 public event System.Action OnValueChanged; public event System.Action OnSpinComplete; public event System.Action OnSpinStart; public event System.Action OnLargeNumberDetected; // 大数字检测事件 #region Unity生命周期 private void Awake() { InitializeWheels(); } private void Start() { if (audioSource == null) audioSource = GetComponent(); } #endregion #region 初始化 private void InitializeWheels() { // 确保有足够的数字轮 while (digitWheels.Count < maxDigits) { digitWheels.Add(new DigitWheel()); } foreach (var wheel in digitWheels) { if (wheel.wheelContainer != null && wheel.digitTexts.Count == 0) { CreateDigitTexts(wheel); } SetupWheelPositions(wheel); } } private void CreateDigitTexts(DigitWheel wheel) { // 为每个数字(0-9)创建文本组件,加上重复的首尾数字用于循环效果 for (int i = 0; i < 12; i++) // 0,1,2,3,4,5,6,7,8,9,0,1 { GameObject digitObj = new GameObject($"Digit_{i % 10}"); digitObj.transform.SetParent(wheel.wheelContainer); Text digitText = digitObj.AddComponent(); digitText.text = (i % 10).ToString(); digitText.fontSize = 36; digitText.alignment = TextAnchor.MiddleCenter; digitText.color = Color.white; // 设置默认字体 digitText.font = Resources.GetBuiltinResource("Arial.ttf"); RectTransform rectTransform = digitText.rectTransform; rectTransform.sizeDelta = new Vector2(digitHeight, digitHeight); rectTransform.localScale = Vector3.one; wheel.digitTexts.Add(digitText); } } private void SetupWheelPositions(DigitWheel wheel) { if (wheel.digitTexts.Count == 0) return; for (int i = 0; i < wheel.digitTexts.Count; i++) { RectTransform rectTransform = wheel.digitTexts[i].rectTransform; rectTransform.localPosition = new Vector3(0, (i - 1) * digitHeight, 0); } } #endregion #region 大数字检测和优化 /// /// 检查是否为大数字 /// private bool IsLargeNumber(long value) { return enableLargeNumberMode && value >= largeNumberThreshold; } /// /// 获取大数字等级 (1=大数字, 2=超大数字, 3=极大数字) /// private int GetLargeNumberLevel(long value) { if (value >= 1000000000000) return 3; // 万亿级 if (value >= 10000000000) return 2; // 百亿级 if (value >= largeNumberThreshold) return 1; // 千万级 return 0; } /// /// 根据数字大小计算优化参数 /// private (float duration, float delay, int minSpins, int maxSpins) CalculateLargeNumberParams(long value) { int level = GetLargeNumberLevel(value); float duration = baseDuration; float delay = digitDelay; int minSpins = 3; int maxSpins = 8; switch (level) { case 1: // 大数字 duration *= largeNumberSpeedMultiplier; delay *= largeNumberDelayReduction; minSpins = largeNumberMinSpins; maxSpins = largeNumberMaxSpins; break; case 2: // 超大数字 duration *= largeNumberSpeedMultiplier * 1.2f; delay *= largeNumberDelayReduction * 0.8f; minSpins = largeNumberMinSpins + 2; maxSpins = largeNumberMaxSpins + 3; break; case 3: // 极大数字 duration *= largeNumberSpeedMultiplier * 1.5f; delay *= largeNumberDelayReduction * 0.6f; minSpins = largeNumberMinSpins + 4; maxSpins = largeNumberMaxSpins + 5; break; } return (duration, delay, minSpins, maxSpins); } #endregion #region 公共方法 /// /// 设置数值(无动画) /// public void SetValue(long value) { currentValue = value; targetValue = value; UpdateDisplayImmediate(value); OnValueChanged?.Invoke(value); if (debugMode) Debug.Log($"FlipNumber: Set value to {value:N0}"); } /// /// 滚动到目标值 /// public void SpinToValue(long targetValue, float? customDuration = null) { if (isAnimating) { StopAllSpins(); } this.targetValue = targetValue; // 检测大数字并触发事件 if (IsLargeNumber(targetValue)) { OnLargeNumberDetected?.Invoke(targetValue); if (debugMode) Debug.Log($"FlipNumber: Large number detected: {targetValue:N0} (Level {GetLargeNumberLevel(targetValue)})"); } StartCoroutine(SpinSequence(currentValue, targetValue, customDuration)); if (debugMode) Debug.Log($"FlipNumber: Spinning from {currentValue:N0} to {targetValue:N0}"); } /// /// 增加数值 /// public void AddValue(long addAmount, float? customDuration = null) { long newTarget = currentValue + addAmount; SpinToValue(newTarget, customDuration); } /// /// 停止所有滚动 /// public void StopAllSpins() { if (!isAnimating) return; StopAllCoroutines(); isAnimating = false; foreach (var wheel in digitWheels) { if (wheel.spinCoroutine != null) { StopCoroutine(wheel.spinCoroutine); wheel.spinCoroutine = null; } wheel.isSpinning = false; } UpdateDisplayImmediate(targetValue); currentValue = targetValue; } #endregion #region 滚动动画 private IEnumerator SpinSequence(long startValue, long endValue, float? customDuration) { isAnimating = true; OnSpinStart?.Invoke(); // 根据数字大小选择音效 AudioClip soundToPlay = IsLargeNumber(endValue) && largeNumberSound != null ? largeNumberSound : spinSound; // 播放滚动音效 if (soundToPlay != null && audioSource != null) { audioSource.clip = soundToPlay; audioSource.loop = true; audioSource.Play(); } string startStr = startValue.ToString().PadLeft(maxDigits, '0'); string endStr = endValue.ToString().PadLeft(maxDigits, '0'); // 获取大数字优化参数 var (optimizedDuration, optimizedDelay, minSpins, maxSpins) = CalculateLargeNumberParams(endValue); // 计算动画时长 float totalDuration = customDuration ?? (optimizedDuration + (endStr.Length * extraDurationPerDigit)); if (debugMode && IsLargeNumber(endValue)) { Debug.Log($"FlipNumber: Using large number optimization - Duration: {totalDuration:F2}s, Delay: {optimizedDelay:F2}s, Spins: {minSpins}-{maxSpins}"); } // 按顺序启动每个数字轮的滚动 List spinCoroutines = new List(); for (int i = 0; i < digitWheels.Count && i < endStr.Length; i++) { int digitIndex = spinFromRightToLeft ? (endStr.Length - 1 - i) : i; if (digitIndex < digitWheels.Count) { int startDigit = digitIndex < startStr.Length ? int.Parse(startStr[digitIndex].ToString()) : 0; int endDigit = int.Parse(endStr[digitIndex].ToString()); yield return new WaitForSeconds(optimizedDelay); Coroutine spinCoroutine = StartCoroutine(SpinDigitWheel( digitWheels[digitIndex], startDigit, endDigit, totalDuration - (i * optimizedDelay), minSpins, maxSpins )); spinCoroutines.Add(spinCoroutine); } } // 等待所有滚动完成 while (spinCoroutines.Count > 0) { for (int i = spinCoroutines.Count - 1; i >= 0; i--) { if (spinCoroutines[i] == null) { spinCoroutines.RemoveAt(i); } } yield return null; } // 停止音效,播放停止音效 if (audioSource != null) { audioSource.Stop(); if (stopSound != null) { audioSource.PlayOneShot(stopSound); } } currentValue = endValue; isAnimating = false; OnValueChanged?.Invoke(currentValue); OnSpinComplete?.Invoke(currentValue); if (debugMode) Debug.Log($"FlipNumber: Spin completed at {currentValue:N0}"); } private IEnumerator SpinDigitWheel(DigitWheel wheel, int startDigit, int endDigit, float duration, int minSpins, int maxSpins) { if (wheel.wheelContainer == null || wheel.digitTexts.Count == 0) yield break; wheel.isSpinning = true; float elapsedTime = 0f; // 计算总的旋转圈数和最终位置 int totalSpins = Random.Range(minSpins, maxSpins + 1); float totalRotation = (totalSpins * 10 + (endDigit - startDigit + 10) % 10) * digitHeight; float startY = -startDigit * digitHeight; float endY = startY - totalRotation; while (elapsedTime < duration) { elapsedTime += Time.deltaTime; float progress = elapsedTime / duration; float curveProgress = wheel.spinCurve.Evaluate(progress); float currentY = Mathf.Lerp(startY, endY, curveProgress); wheel.wheelContainer.localPosition = new Vector3(0, currentY, 0); // 大数字华丽效果:动态缩放 if (enableSpectacularEffect && IsLargeNumber(targetValue)) { float scaleEffect = 1f + Mathf.Sin(progress * Mathf.PI * 6) * 0.05f; // 轻微的缩放动画 wheel.wheelContainer.localScale = Vector3.one * scaleEffect; } yield return null; } // 确保最终位置和缩放正确 wheel.wheelContainer.localPosition = new Vector3(0, -endDigit * digitHeight, 0); wheel.wheelContainer.localScale = Vector3.one; wheel.currentDigit = endDigit; wheel.isSpinning = false; wheel.spinCoroutine = null; } #endregion #region 显示更新 private void UpdateDisplayImmediate(long value) { string valueStr = value.ToString().PadLeft(maxDigits, '0'); for (int i = 0; i < digitWheels.Count && i < valueStr.Length; i++) { int digit = int.Parse(valueStr[i].ToString()); var wheel = digitWheels[i]; if (wheel.wheelContainer != null) { wheel.wheelContainer.localPosition = new Vector3(0, -digit * digitHeight, 0); wheel.wheelContainer.localScale = Vector3.one; wheel.currentDigit = digit; } } } #endregion #region 属性访问器 public long CurrentValue => currentValue; public long TargetValue => targetValue; public bool IsAnimating => isAnimating; public bool IsCurrentValueLarge => IsLargeNumber(currentValue); public int CurrentLargeNumberLevel => GetLargeNumberLevel(currentValue); #endregion #region 工具方法 /// /// 设置数字轮的颜色 /// public void SetDigitColor(Color color) { foreach (var wheel in digitWheels) { foreach (var digitText in wheel.digitTexts) { if (digitText != null) digitText.color = color; } } } /// /// 设置数字轮的字体大小 /// public void SetFontSize(int fontSize) { foreach (var wheel in digitWheels) { foreach (var digitText in wheel.digitTexts) { if (digitText != null) digitText.fontSize = fontSize; } } } /// /// 为大数字设置特殊颜色效果 /// public void SetLargeNumberColorEffect(Color normalColor, Color largeNumberColor) { Color colorToUse = IsLargeNumber(currentValue) ? largeNumberColor : normalColor; SetDigitColor(colorToUse); } #endregion #region 调试方法 [ContextMenu("Test Spin +1000")] private void TestSpin1000() { AddValue(1000); } [ContextMenu("Test Spin +10000")] private void TestSpin10000() { AddValue(10000); } [ContextMenu("Test Large Number 50000000")] private void TestLargeNumber() { SpinToValue(50000000); // 5千万 } [ContextMenu("Test Ultra Large Number 5000000000")] private void TestUltraLargeNumber() { SpinToValue(5000000000); // 50亿 } [ContextMenu("Test Mega Jackpot 999999999999")] private void TestMegaJackpot() { SpinToValue(999999999999); // 接近万亿 } [ContextMenu("Test Reset to 0")] private void TestReset() { SetValue(0); } #endregion } } ```