unity简易计时器,延迟回调,循环

分享项目中的一个简单的计时器,在设定时间后回调函数。

using System.Collections.Generic;
using UnityEngine;
using System;

namespace XRTool.Util
{
    public delegate void TimerHandler();

    public delegate void TimerArgsHandler(object[] args);

    public class Timer
    {
        public TimerHandler Handler;           //无参的委托
        public TimerArgsHandler ArgsHandler;   //带参数的委托
        public float Frequency;               //时间间隔
        public int Repeats;                   //重复次数
        public object[] Args;

        public float LastTickTime;

        public event Action OnComplete;        //计时器完成一次工作
        public event Action OnDestroy;        //计时器被销毁
        public event Action OnFinsh;        //计时器结束工作了
        public Timer() { }

        /// <summary>
        /// 创建一个时间事件对象
        /// </summary>
        /// <param name="Handler">回调函数</param>
        /// <param name="ArgsHandler">带参数的回调函数</param>
        /// <param name="frequency">时间内执行</param>
        /// <param name="repeats">重复次数</param>
        /// <param name="Args">参数  可以任意的传不定数量,类型的参数</param>
        public Timer(TimerHandler Handler, TimerArgsHandler ArgsHandler, float frequency, int repeats, object[] Args)
        {
            this.Handler = Handler;
            this.ArgsHandler = ArgsHandler;
            this.Frequency = frequency;
            this.Repeats = repeats == 0 ? 1 : repeats;
            this.Args = Args;
            this.LastTickTime = Time.time;
        }

        public void Notify()
        {
            Handler?.Invoke();
            ArgsHandler?.Invoke(Args);
            OnComplete?.Invoke();
        }
        /// <summary>
        /// 清理计时器,初始化参数  同时清理事件
        /// </summary>
        public void CleanUp()
        {
            Handler = null;
            ArgsHandler = null;
            Repeats = 1;
            Frequency = 0;
            OnDestroy?.Invoke();
            OnFinsh?.Invoke();
            OnDestroy = null;
            OnComplete = null;
        }
        /// <summary>
        /// 立即执行回调
        /// isBreak = false的时候需要根据是否继续执行,传time
        /// isBreak = true,可不传time
        /// </summary>
        /// <param name="time">当前的时间,Time.time</param>
        /// <param name="isBreak">执行完之后是否销毁计时器</param>
        public void AwakeNow(float time = 0, bool isBreak = true)
        {
            try
            {
                ///唤醒可能会有异常
                Notify();
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
                Debug.LogError(ex.ToString());
            }
            finally
            {
                if (isBreak)
                {
                    OnFinsh?.Invoke();
                    TimerMgr.Instance.DestroyTimer(this);
                }
                else
                {
                    if ((--Repeats) == 0)
                    {
                        OnFinsh?.Invoke();
                        TimerMgr.Instance.DestroyTimer(this);
                    }
                    else
                    {
                        LastTickTime = time;
                    }
                }
            }
        }
        /// <summary>
        /// 根据当前时间判断是否要触发触发器
        /// </summary>
        /// <param name="time"></param>
        public void Update(float time)
        {
            if (Frequency + LastTickTime <= time)
            {
                AwakeNow(time, false);
            }
        }
    }

    /// <summary>
    /// 计时器
    /// 添加一个计时事件
    /// 删除一个计时事件
    /// 更新计时事件
    /// </summary>
    public class TimerMgr : MonoBehaviour
    {
        private List<Timer> _Timers;//时间管理器
        public static TimerMgr Instance;
        void Awake()
        {
            DontDestroyOnLoad(gameObject);
            if (_Timers == null)
            {
                _Timers = new List<Timer>();
            }
            Instance = this;
        }
        /// <summary>
        /// 创建一个简单的计时器
        /// </summary>
        /// <param name="callBack">回调函数</param>
        /// <param name="time">计时器时间</param>
        /// <param name="repeats">回调次数  小于0代表循环 大于0代表repeats次</param>
        public Timer CreateTimer(TimerHandler callBack, float time, int repeats = 1)
        {
            return Create(callBack, null, time, repeats);
        }

        public Timer CreateTimer(TimerArgsHandler callBack, float time, int repeats, params object[] args)
        {
            return Create(null, callBack, time, repeats, args);
        }

        private Timer Create(TimerHandler callBack, TimerArgsHandler callBackArgs, float time, int repeats, params object[] args)
        {
            Timer timer = new Timer(callBack, callBackArgs, time, repeats, args);
            _Timers.Add(timer);
            return timer;
        }

        public Timer DestroyTimer(Timer timer)
        {
            if (timer != null)
            {
                _Timers.Remove(timer);
                timer.CleanUp();
                timer = null;
            }
            return timer;
        }
        /// <summary>
        /// 禁止调用此函数
        /// </summary>
        public void ClearAll()
        {
            if (_Timers != null)
            {
                for (int i = 0; i < _Timers.Count; i++)
                {
                    _Timers[i].CleanUp();
                }
                _Timers.Clear();
            }
        }
        /// <summary>
        /// 固定更新检查更新的频率
        /// </summary>
        private void Update()
        {
            if (_Timers.Count != 0)
            {
                for (int i = _Timers.Count - 1; i >= 0 && i < _Timers.Count; i--)
                {
                    _Timers[i].Update(Time.time);
                }
            }
        }
    }
}

代码使用也简单,计时器为单例模式,将代码挂载在场景中即可。
在这里插入图片描述
我们新建一个test测试代码,用来展示如何使用计时器。
在这里插入图片描述
在这里插入图片描述

 TimerMgr.Instance.CreateTimer(() => { Debug.Log("zhixing1"); }, 1f);

上述代码就是在一秒以后执行一个debug输出“zhixing1”,我们在场景中运行后看看结果。
在这里插入图片描述
显示一秒之后执行了我们的回调。在试试循环。

 TimerMgr.Instance.CreateTimer(() => { Debug.Log("zhixing2循环"); }, 3f, -1);

在这里插入图片描述
看到结果3秒就循环执行一次我们的代码。
执行带参回调。
在这里插入图片描述

 TimerMgr.Instance.CreateTimer(() => { Log(1); }, 1f, 1);

在这里插入图片描述
正常执行。
分享到这。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值