让数字变化炫酷起来,数字滚动Text组件[Unity]

让数字滚动起来

上周我的策划又提了样需求,当玩家评分发生变动时,屏幕出现人物评分浮层UI,播放评分数字滚动动画。这类数字滚动需求非常常见,我就按一般思路,将startvalue与endvalue每隔一点时间做插值变化并显示,从而实现数字滚动的效果,这也是大部分app及游戏采取的实现,效果如下:

几行代码写完给策划看效果,策划说不是这样的效果,跟XX游戏做得不一样,得像lao虎机数字一样,有真实的数字滚动效果,好吧,此滚动非彼滚动,期望效果应该是下面这样,看起来更确实炫酷:

代码实现

这样的效果也不难实现,但要注意一些细节,让动画看起来更真实:

  1. 仍然每隔一点时间做插值变化,算出插值后,不再是简单地修改Text内容了,而是准备用另一个Text显示新值,2个Text都自底向上做缓动,造成像lao虎机一样,新值顶掉旧值的动画效果,要注意每一位数字都单独使用Text组件显示。我们游戏里的战力固定6位数显示,所以总共设置了12个Text组件。
  2. 错开每一位数字的滚动时间点,让滚动效果看起来更自然。设置一个Delay变量,从个位起,后面的每一位都增加一倍Delay再滚动。

/* ==============================================================================
 * 功能描述:数字动态变化Text
 * 创 建 者:shuchangliu
 * ==============================================================================*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

public class JumpingNumberTextComponent : MonoBehaviour
{
    [SerializeField]
    [Tooltip("按最高位起始顺序设置每位数字Text(显示组)")]
    private List<Text> _numbers; 
    [SerializeField]
    [Tooltip("按最高位起始顺序设置每位数字Text(替换组)")]
    private List<Text> _unactiveNumbers;
    /// <summary>
    /// 动画时长
    /// </summary>
    [SerializeField]
    private float _duration = 1.5f;
    /// <summary>
    /// 数字每次滚动时长
    /// </summary>
    [SerializeField]
    private float _rollingDuration = 0.05f;
    /// <summary>
    /// 数字每次变动数值
    /// </summary>
    private int _speed;
    /// <summary>
    /// 滚动延迟(每进一位增加一倍延迟,让滚动看起来更随机自然)
    /// </summary>
    [SerializeField]
    private float _delay = 0.008f;
    /// <summary>
    /// Text文字宽高
    /// </summary>
    private Vector2 _numberSize;
    /// <summary>
    /// 当前数字
    /// </summary>
    private int _curNumber;
    /// <summary>
    /// 起始数字
    /// </summary>
    private int _fromNumber;
    /// <summary>
    /// 最终数字
    /// </summary>
    private int _toNumber;
    /// <summary>
    /// 各位数字的缓动实例
    /// </summary>
    private List<Tweener> _tweener = new List<Tweener>();
    /// <summary>
    /// 是否处于数字滚动中
    /// </summary>
    private bool _isJumping;
    /// <summary>
    /// 滚动完毕回调
    /// </summary>
    public Action OnComplete;

    private void Awake()
    {
        if (_numbers.Count == 0 || _unactiveNumbers.Count == 0)
        {
            MediaUnity.Debugger.LogError("[JumpingNumberTextComponent] 还未设置Text组件!");
            return;
        }
        _numberSize = _numbers[0].rectTransform.sizeDelta;
    }

    public float duration
    {
        get { return _duration; }
        set
        {
            _duration = value;
        }
    }

    private float _different;
    public float different
    {
        get { return _different; }
    }

    public void Change(int from, int to)
    {
        bool isRepeatCall = _isJumping && _fromNumber == from && _toNumber == to;
        if (isRepeatCall) return;

        bool isContinuousChange = (_toNumber == from) && ((to - from > 0 && _different > 0) || (to - from < 0 && _different < 0));
        if (_isJumping && isContinuousChange)
        {
        }
        else
        {
            _fromNumber = from;
            _curNumber = _fromNumber;
        }
        _toNumber = to;

        _different = _toNumber - _fromNumber;
        _speed = (int)Math.Ceiling(_different / (_duration * (1 / _rollingDuration)));
        _speed = _speed == 0 ? (_different > 0 ? 1 : -1) : _speed;

        SetNumber(_curNumber, false);
        _isJumping = true;
        StopCoroutine("DoJumpNumber");
        StartCoroutine("DoJumpNumber");  
    }

    public int number
    {
        get { return _toNumber; }
        set
        {
            if (_toNumber == value) return;
            Change(_curNumber, _toNumber);
        }
    }
    
    IEnumerator DoJumpNumber()
    {
        while (true)
        {
            if (_speed > 0)//增加
            {
                _curNumber = Math.Min(_curNumber + _speed, _toNumber);
            }
            else if (_speed < 0) //减少
            {
                _curNumber = Math.Max(_curNumber + _speed, _toNumber);
            }
            SetNumber(_curNumber, true);

            if (_curNumber == _toNumber)
            {
                StopCoroutine("DoJumpNumber");
                _isJumping = false;
                if (OnComplete != null) OnComplete();
                yield return null;
            }
            yield return new WaitForSeconds(_rollingDuration);
        }
    }

    /// <summary>
    /// 设置战力数字
    /// </summary>
    /// <param name="v"></param>
    /// <param name="isTween"></param>
    public void SetNumber(int v, bool isTween)
    {
        char[] c = v.ToString().ToCharArray();
        Array.Reverse(c);
        string s = new string(c);

        if (!isTween)
        {
            for (int i = 0; i < _numbers.Count; i++)
            {
                if (i < s.Count())
                    _numbers[i].text = s[i] + "";
                else
                    _numbers[i].text = "0";
            }
        }
        else
        {
            while (_tweener.Count > 0)
            {
                _tweener[0].Complete();
                _tweener.RemoveAt(0);
            }

            for (int i = 0; i < _numbers.Count; i++)
            {
                if (i < s.Count())
                {
                    _unactiveNumbers[i].text = s[i] + "";
                }
                else
                {
                    _unactiveNumbers[i].text = "0";
                }

                _unactiveNumbers[i].rectTransform.anchoredPosition = new Vector2(_unactiveNumbers[i].rectTransform.anchoredPosition.x, (_speed > 0 ? -1 : 1) * _numberSize.y);
                _numbers[i].rectTransform.anchoredPosition = new Vector2(_unactiveNumbers[i].rectTransform.anchoredPosition.x, 0);

                if (_unactiveNumbers[i].text != _numbers[i].text)
                {
                    DoTween(_numbers[i], (_speed > 0 ? 1 : -1) * _numberSize.y, _delay * i);
                    DoTween(_unactiveNumbers[i], 0, _delay * i);

                    Text tmp = _numbers[i];
                    _numbers[i] = _unactiveNumbers[i];
                    _unactiveNumbers[i] = tmp;
                }
            }
        }
    }

    public void DoTween(Text text, float endValue, float delay)
    {
        Tweener t = DOTween.To(() => text.rectTransform.anchoredPosition, (x) =>
        {
            text.rectTransform.anchoredPosition = x;
        }, new Vector2(text.rectTransform.anchoredPosition.x, endValue), _rollingDuration - delay).SetDelay(delay);
        _tweener.Add(t);
    }


    [ContextMenu("测试数字变化")]
    public void TestChange()
    {
        Change(UnityEngine.Random.Range(1, 1), UnityEngine.Random.Range(1, 100000));
    }

}
标签:  游戏开发Unity

猜你喜欢

转载自blog.csdn.net/AGroupOfRuffian/article/details/80050098