Unity计时器(实现暂停,继续等功能)

       计时器是游戏开发的一个非常常用的功能,简单计时器的实现方式有很多中,可以每帧给一个float变量加Time.deltaTime,到一定时间的时候调用某个函数。也可以使用unity的协程和InvokeRepeating。但是简单的使用这些组合调用起来不是很方便,并且无法实现暂停,继续等功能,也无法在计时器运行到某个时间点的时候移除或者添加新的事件。

1.计时器

       这个计时器用到了之前文章里的Singleton和MonoEvent,链接在此  Unity单例模式及MonoEvent

       直接上代码,注释也很详细,后面再写上使用方式。一共两个类,一个Timer是计时器,TimeManager由于只在Timer中用到,直接定义在Timer里面。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OnEventDelegate = System.Action;

public class Timer
{
    private OnEventDelegate timeUpDel;
    /// <summary>
    /// 是否执行
    /// </summary>
    private bool _isRunning;
    /// <summary>
    /// 已执行时间(每次满足运行间隔就会加这个)
    /// </summary>
    private float _useTime;
    /// <summary>
    /// 运行时间
    /// </summary>
    public float RunTime { get; private set; }
    /// <summary>
    /// 已运行次数
    /// </summary>
    public int UseCount { get; private set; }
    /// <summary>
    /// 运行间隔
    /// </summary>
    public float TimeInterval { get; set; }
    /// <summary>
    /// 设置的运行次数
    /// </summary>
    public int RepeatCount { get; set; }

    /// <summary>
    /// <param name="interval">时间间隔,单位是毫秒</param>
    /// <param name="repeatCount">运行次数,一秒一次的话MaxValue可以执行68年</param>
    /// </summary>
    public Timer(float interval, int repeatCount = int.MaxValue)
    {
        RunTime = 0f;
        TimeInterval = Mathf.Max(interval, 1);  // 最小间隔为1毫秒
        RepeatCount = repeatCount;
    }

    /// <summary>
    /// 是否运行中
    /// </summary>
    public bool IsRunning
    {
        get { return _isRunning; }
        set
        {
            if (_isRunning != value)
            {
                _isRunning = value;
                if (_isRunning)
                {
                    TimerManager.Instance.AddTimer(this);
                }
                else
                {
                    TimerManager.Instance.RemoveTimer(this);
                }
                //这里可以加一个计时器状态变换的委托
            }
        }
    }

    /// <summary>
    /// 每帧执行
    /// </summary>
    /// <param name="deltaTime"></param>
    public void Update(float deltaTime)
    {
        if (IsRunning && UseCount < RepeatCount)
        {
            RunTime += deltaTime;
            var f = TimeInterval / 1000;
            while (RunTime - _useTime > f && UseCount < RepeatCount)
            {
                UseCount++;
                _useTime += f;
                timeUpDel?.Invoke();
            }
        }
        if (UseCount >= RepeatCount)
        {
            IsRunning = false;
        }
    }

    /// <summary>
    /// 添加事件
    /// </summary>
    /// <param name="type"></param>
    /// <param name="fun"></param>
    public void AddEventListener(OnEventDelegate fun)
    {
        timeUpDel += fun;
    }

    /// <summary>
    /// 移除事件
    /// </summary>
    /// <param name="type"></param>
    /// <param name="fun"></param>
    public void RemoveEventListener(OnEventDelegate fun)
    {
        timeUpDel -= fun;
    }

    /// <summary>
    /// 开始(调用了IsRunning的Set,初始化了TimerManager)
    /// </summary>
    public void Start()
    {
        IsRunning = true;
    }

    /// <summary>
    /// 停止
    /// </summary>
    public void Pause()
    {
        IsRunning = false;
    }

    /// <summary>
    /// 重置
    /// </summary>
    public void ReSet()
    {
        IsRunning = false;
        RunTime = 0f;
        _useTime = 0f;
        UseCount = 0;
    }

    /// <summary>
    /// 计时器管理
    /// 除了计时器以外其他类暂时不需要调用,以后需要再放到外面去
    /// </summary>
    public class TimerManager : Singleton<TimerManager>
    {

        private readonly List<Timer> _timers = new List<Timer>();

        public TimerManager()
        {
            MonoEvent.Instance.LATEUPDATE += LateUpdate;
        }

        private void LateUpdate()
        {
            for (var i = 0; i < _timers.Count; i++)
            {
                if (_timers[i].IsRunning)
                {
                    // unscaledDeltaTime和deltaTime一样,但是不受TimeScale影响
                    _timers[i].Update(Time.unscaledDeltaTime);
                }
            }
        }

        public void AddTimer(Timer timer)
        {
            if (_timers.Contains(timer) == false)
            {
                _timers.Add(timer);
            }
        }

        public void RemoveTimer(Timer timer)
        {
            if (_timers.Contains(timer))
            {
                _timers.Remove(timer);
            }
        }
    }
}

2.使用方式

步骤一:构造

Timer timer = new Timer(1000,3);      //  计时器的构造以毫秒为单位,这是一个没秒触发一次,触发三次结束的计时器

步骤二:添加事件

事件的添加和Button的onClick.AddListener()一样,将函数当参数传入,也可以使用Lambda表达式

timer.AddEventListener(() =>
{
    Debug.Log("new time");
});

对应的还有移除事件

timer.RemoveEventListener

步骤三:操作

timer.Start();      // 开始
timer.Pause();   //  暂停
timer.ReSet();   //   重置

暂停后继续计时器也调用timer.Start();

猜你喜欢

转载自blog.csdn.net/xdedzl/article/details/85054888