C#--定时回调系统:unity中定时器的实现

开发基于C#语言实现的高效便捷计时器工具,可集成中在服务器(.net core/.net framework)以及Unity客户端环境中。定时任务可循环、可替换、可取消。可使用独立线程计时,也可以使用Update()驱动计时。自由集成,灵活性高。

开发目标:

1.支持时间定时

2.定时任务可循环,可取消,可替换

3.使用简单,调用方便

 

时间定时:

场景中创建一个Button组件,挂上GameRoot、TimerSystem脚本;

using UnityEngine;

public class GameRoot : MonoBehaviour {

    private void Start()
    {
        TimerSystem timerSystem = GetComponent();
        timerSystem.InitTimer();
    }

    public void ClickBtn()
    {
        Debug.Log("Add Time Task");
        TimerSystem._instance.AddTimerTask(FuncA,3.0f);
    }

    void FuncA()
    {
        Debug.Log("Delay Log");
    }
}
using System;

public class PETimeTask
{
    public float destTime;//多少时间后执行任务
    public Action callBack;// 要执行什么任务
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class TimerSystem : MonoBehaviour
{

    public static TimerSystem _instance;
    private List mTimerTaskList = new List();

    public void InitTimer()
    {
        _instance = this;
    }

    private void Update()
    {
        //遍历检测任务是否达到条件
        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            PETimeTask timeTask = mTimerTaskList[i];
            //任务时间超过当前时间
            if (timeTask.destTime > Time.realtimeSinceStartup)
            {
                continue;
            }
            else
            {
                Action action = timeTask.callBack;
                if (action != null)
                {
                    action();
                }
                //移除已经完成的任务
                mTimerTaskList.RemoveAt(i);
                i--;
            }
        }
    }

    //添加计时器任务
    public void AddTimerTask(Action callBack, float delay)
    {
        float destTime = Time.realtimeSinceStartup + delay;
        PETimeTask task = new PETimeTask();
        task.callBack = callBack;
        task.destTime = destTime;
        mTimerTaskList.Add(task);
    }
}

以上实现类似协程的效果↑

 

如何支持多线程定时任务?

--通过临时列表进行缓存,错开操作时间

--避免使用锁,提高操作效率

添加临时缓存列表:

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

public class TimerSystem : MonoBehaviour
{

    public static TimerSystem _instance;
    private List mTimerTaskList = new List();
    //临时缓存列表
    private List mTempTimeTaskList = new List();

    public void InitTimer()
    {
        _instance = this;
    }

    private void Update()
    {
        //加入缓存区中的定时任务
        for (int tempIndex = 0; tempIndex < mTempTimeTaskList.Count; tempIndex++)
        {
            mTimerTaskList.Add(mTempTimeTaskList[tempIndex]);
        }
        mTempTimeTaskList.Clear();

        //遍历检测任务是否达到条件
        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            PETimeTask timeTask = mTimerTaskList[i];
            //任务时间超过当前时间
            if (timeTask.destTime > Time.realtimeSinceStartup)
            {
                continue;
            }
            else
            {
                Action action = timeTask.callBack;
                if (action != null)
                {
                    action();
                }
                //移除已经完成的任务
                mTimerTaskList.RemoveAt(i);
                i--;
            }
        }
    }

    //添加计时器任务
    public void AddTimerTask(Action callBack, float delay)
    {
        float destTime = Time.realtimeSinceStartup + delay;
        PETimeTask task = new PETimeTask();
        task.callBack = callBack;
        task.destTime = destTime;
        mTempTimeTaskList.Add(task);
    }
}

扩展时间单位:

统一换算成最小的单位毫秒进行运算

using System;

public class PETimeTask
{
    public float destTime;//多少时间后执行任务 单位为毫秒
    public Action callBack;// 要执行什么任务
}

扩展时间单位
public enum PETimeUnit
{
    Millise,
    Second,
    Minute,
    Hour,
    Day
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class TimerSystem : MonoBehaviour
{

    public static TimerSystem _instance;
    private List mTimerTaskList = new List();
    //临时缓存列表
    private List mTempTimeTaskList = new List();

    public void InitTimer()
    {
        _instance = this;
    }

    //实现基础定时任务
    private void Update()
    {
        //加入缓存区中的定时任务
        for (int tempIndex = 0; tempIndex < mTempTimeTaskList.Count; tempIndex++)
        {
            mTimerTaskList.Add(mTempTimeTaskList[tempIndex]);
        }
        mTempTimeTaskList.Clear();

        //遍历检测任务是否达到条件
        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            PETimeTask timeTask = mTimerTaskList[i];
            //任务时间超过当前时间
            if (timeTask.destTime > Time.realtimeSinceStartup *1000 )
            {
                continue;
            }
            else
            {
                Action action = timeTask.callBack;
                if (action != null)
                {
                    action();
                }
                //移除已经完成的任务
                mTimerTaskList.RemoveAt(i);
                i--;
            }
        }
    }

    //添加计时器任务
    public void AddTimerTask(Action callBack, float delay,PETimeUnit timeUnit = PETimeUnit.Millise)
    {
        if (timeUnit != PETimeUnit.Millise)
        {
            switch (timeUnit)
            {
                case PETimeUnit.Second:
                    delay = delay * 1000;
                    break;
                case PETimeUnit.Minute:
                    delay = delay * 1000 * 60;
                    break;
                case PETimeUnit.Hour:
                    delay = delay * 1000 * 60 * 60;
                    break;
                case PETimeUnit.Day:
                    delay = delay * 1000 * 60 * 60 * 24;
                    break;
                default:
                    Debug.LogWarning("Time Task Type Is Error...");
                    break;
            }
        }

        float destTime = Time.realtimeSinceStartup *1000 + delay;
        PETimeTask task = new PETimeTask();
        task.callBack = callBack;
        task.destTime = destTime;
        mTempTimeTaskList.Add(task);
    }
}

实现任务可循环功能:(在添加任务的方法中加入循环次数的参数)

using System;

public class PETimeTask
{
    public Action callBack;// 要执行什么任务
    public float destTime;//多少时间后执行任务 单位为毫秒
    public float count;//执行任务的次数
    public float delay;//延迟的时间

    public PETimeTask(Action callBack,float destTime,float delay, float count)
    {
        this.callBack = callBack;
        this.destTime = destTime;
        this.count = count;
        this.delay = delay;
    }
}

public enum PETimeUnit
{
    Millise,
    Second,
    Minute,
    Hour,
    Day
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class TimerSystem : MonoBehaviour
{

    public static TimerSystem _instance;
    private List mTimerTaskList = new List();
    //临时缓存列表
    private List mTempTimeTaskList = new List();

    public void InitTimer()
    {
        _instance = this;
    }


    //实现基础定时任务
    private void Update()
    {
        //加入缓存区中的定时任务
        for (int tempIndex = 0; tempIndex < mTempTimeTaskList.Count; tempIndex++)
        {
            mTimerTaskList.Add(mTempTimeTaskList[tempIndex]);
        }
        mTempTimeTaskList.Clear();

        //遍历检测任务是否达到条件
        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            PETimeTask timeTask = mTimerTaskList[i];
            //任务时间超过当前时间
            if (timeTask.destTime > Time.realtimeSinceStartup *1000 )
            {
                continue;
            }
            else
            {
                Action action = timeTask.callBack;
                if (action != null)
                {
                    action();
                }
                //移除已经完成的任务
                if (timeTask.count == 1)
                {
                    mTimerTaskList.RemoveAt(i);
                    i--;
                }
                else
                {
                    if (timeTask.count != 0)
                    {
                        timeTask.count -= 1;
                    }
                    timeTask.destTime += timeTask.delay;
                }
            }
        }
    }

    //添加计时器任务
    public void AddTimerTask(Action callBack, float delay, int count = 1,PETimeUnit timeUnit = PETimeUnit.Millise)
    {
        if (timeUnit != PETimeUnit.Millise)
        {
            switch (timeUnit)
            {
                case PETimeUnit.Second:
                    delay = delay * 1000;
                    break;
                case PETimeUnit.Minute:
                    delay = delay * 1000 * 60;
                    break;
                case PETimeUnit.Hour:
                    delay = delay * 1000 * 60 * 60;
                    break;
                case PETimeUnit.Day:
                    delay = delay * 1000 * 60 * 60 * 24;
                    break;
                default:
                    Debug.LogWarning("Time Task Type Is Error...");
                    break;
            }
        }

        float destTime = Time.realtimeSinceStartup *1000 + delay;
        mTempTimeTaskList.Add(new PETimeTask(callBack,destTime,delay,count));
    }
}

取消定时任务:

--生成全局唯一ID

--通过ID索引操作任务

 

生成全局ID并通过ID索引取消定时任务:

可创建两个Button,分别挂上ClickBtn和DelectTaskBtn进行测试

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

public class GameRoot : MonoBehaviour {

    int tid;

    private void Start()
    {
        TimerSystem timerSystem = GetComponent();
        timerSystem.InitTimer();
    }

    public void ClickBtn()
    {
        Debug.Log("Add Time Task");
        tid = TimerSystem._instance.AddTimerTask(FuncA,1500,3);
    }

    public void DelectTaskBtn()
    {
       bool res =  TimerSystem._instance.DelectTimeTask(tid);
       Debug.Log("Delect Time Task:" + res);
    }

    void FuncA()
    {
        Debug.Log("Delay Log");
    }
}
using System;

public class PETimeTask
{
    public int tid;
    public Action callBack;// 要执行什么任务
    public float destTime;//多少时间后执行任务 单位为毫秒
    public float count;//执行任务的次数
    public float delay;//延迟的时间

    public PETimeTask(int tid,Action callBack,float destTime,float delay, float count)
    {
        this.tid = tid;
        this.callBack = callBack;
        this.destTime = destTime;
        this.count = count;
        this.delay = delay;
    }
}

public enum PETimeUnit
{
    Millise,
    Second,
    Minute,
    Hour,
    Day
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class TimerSystem : MonoBehaviour
{
    private int tid;//全局ID

    private static readonly string obj = "lock";

    public static TimerSystem _instance;
    private List mTimerTaskList = new List();
    //临时缓存列表
    private List mTempTimeTaskList = new List();
    //存储tid
    private List tidList = new List();

    public void InitTimer()
    {
        _instance = this;
    }


    //实现基础定时任务
    private void Update()
    {
        //加入缓存区中的定时任务
        for (int tempIndex = 0; tempIndex < mTempTimeTaskList.Count; tempIndex++)
        {
            mTimerTaskList.Add(mTempTimeTaskList[tempIndex]);
        }
        mTempTimeTaskList.Clear();

        //遍历检测任务是否达到条件
        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            PETimeTask timeTask = mTimerTaskList[i];
            //任务时间超过当前时间
            if (timeTask.destTime > Time.realtimeSinceStartup * 1000)
            {
                continue;
            }
            else
            {
                Action action = timeTask.callBack;
                if (action != null)
                {
                    action();
                }
                //移除已经完成的任务
                if (timeTask.count == 1)
                {
                    mTimerTaskList.RemoveAt(i);
                    i--;
                }
                else
                {
                    if (timeTask.count != 0)
                    {
                        timeTask.count -= 1;
                    }
                    timeTask.destTime += timeTask.delay;
                }
            }
        }
    }

    //添加计时器任务
    public int AddTimerTask(Action callBack, float delay, int count = 1, PETimeUnit timeUnit = PETimeUnit.Millise)
    {
        if (timeUnit != PETimeUnit.Millise)
        {
            switch (timeUnit)
            {
                case PETimeUnit.Second:
                    delay = delay * 1000;
                    break;
                case PETimeUnit.Minute:
                    delay = delay * 1000 * 60;
                    break;
                case PETimeUnit.Hour:
                    delay = delay * 1000 * 60 * 60;
                    break;
                case PETimeUnit.Day:
                    delay = delay * 1000 * 60 * 60 * 24;
                    break;
                default:
                    Debug.LogWarning("Time Task Type Is Error...");
                    break;
            }
        }

        int tid = GetId();

        float destTime = Time.realtimeSinceStartup * 1000 + delay;
        mTempTimeTaskList.Add(new PETimeTask(tid, callBack, destTime, delay, count));
        tidList.Add(tid);
        return tid;
    }

    public bool DelectTimeTask(int tid)
    {
        bool exist = false;

        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            if (tid == mTimerTaskList[i].tid)
            {
                mTimerTaskList.RemoveAt(i);
                for (int j = 0; j < tidList.Count; j++)
                {
                    if (tid == tidList[j])
                    {
                        tidList.RemoveAt(j);
                        break;
                    }
                }
                exist = true;
                break;
            }
        }

        if (!exist)
        {
            for (int i = 0; i < mTempTimeTaskList.Count; i++)
            {
                if (tid == mTempTimeTaskList[i].tid)
                {
                    mTempTimeTaskList.RemoveAt(i);
                    for (int j = 0; j < tidList.Count; j++)
                    {
                        if (tid == tidList[j])
                        {
                            tidList.RemoveAt(j);
                            break;
                        }
                    }
                    exist = true;
                    break;
                }
            }
        }

        return exist;
    }

    public int GetId()
    {
        //添加计时任务为多线程,多线程生成唯一ID时需要锁防止同时访问生成
        lock (obj)
        {
            tid += 1;

            //安全检测 以防万一
            while (true)
            {
                //tid达到int的最大值时
                if (tid == int.MaxValue)
                {
                    tid = 0;
                }

                bool isUsed = false;

                for (int i = 0; i < tidList.Count; i++)
                {
                    if (tid == tidList[i])
                    {
                        isUsed = true;
                        break;
                    }
                }
                if (!isUsed)
                {
                    break;
                }
                else
                {
                    tid += 1;
                }
            }
        }

        return tid;
    }
}

实现任务替换和清理全局ID功能:

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

public class GameRoot : MonoBehaviour {

    int tid;

    private void Start()
    {
        TimerSystem timerSystem = GetComponent();
        timerSystem.InitTimer();
    }

    public void ClickAddBtn()
    {
        Debug.Log("Add Time Task");
        tid = TimerSystem._instance.AddTimerTask(FuncA,500,0);
    }

    public void ClickDelectBtn()
    {
       bool res =  TimerSystem._instance.DelectTimeTask(tid);
       Debug.Log("Delect Time Task:" + res);
    }

    void FuncA()
    {
        Debug.Log("Delay Log");
    }

    public void ClickReplaceBtn()
    {
        bool res = TimerSystem._instance.ReplaceTimeTask(tid,FuncB,2000);
        Debug.Log("Replace Time Task:" + res);
    }

    void FuncB()
    {
        Debug.Log("Replace Log");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class TimerSystem : MonoBehaviour
{
    private int tid;//全局ID

    private static readonly string obj = "lock";

    public static TimerSystem _instance;
    private List mTimerTaskList = new List();

    //临时缓存列表
    private List mTempTimeTaskList = new List();

    //存储tid
    private List tidList = new List();

    //存储需清理的ID
    private List recIDList = new List();

    public void InitTimer()
    {
        _instance = this;
    }


    //实现基础定时任务
    private void Update()
    {
        //加入缓存区中的定时任务
        for (int tempIndex = 0; tempIndex < mTempTimeTaskList.Count; tempIndex++)
        {
            mTimerTaskList.Add(mTempTimeTaskList[tempIndex]);
        }
        mTempTimeTaskList.Clear();

        //遍历检测任务是否达到条件
        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            PETimeTask timeTask = mTimerTaskList[i];
            //任务时间超过当前时间
            if (timeTask.destTime > Time.realtimeSinceStartup * 1000)
            {
                continue;
            }
            else
            {
                Action action = timeTask.callBack;
                if (action != null)
                {
                    action();
                }
                //移除已经完成的任务
                if (timeTask.count == 1)
                {
                    mTimerTaskList.RemoveAt(i);
                    i--;
                    recIDList.Add(timeTask.tid);
                }
                else
                {
                    if (timeTask.count != 0)
                    {
                        timeTask.count -= 1;
                    }
                    timeTask.destTime += timeTask.delay;
                }
            }
        }

        //当需清理的ID缓存区有东西时,进行清理
        if (recIDList.Count > 0)
        {
            RecycleTid();
        }
    }

    private void RecycleTid()
    {
        for (int i = 0; i < recIDList.Count; i++)
        {
            int tid = recIDList[i];

            for (int j = 0; j < tidList.Count; j++)
            {
                if (tid == tidList[j])
                {
                    tidList.RemoveAt(j);
                    break;
                }
            }
        }
        recIDList.Clear();
    }

    //添加计时器任务
    public int AddTimerTask(Action callBack, float delay, int count = 1, PETimeUnit timeUnit = PETimeUnit.Millise)
    {
        if (timeUnit != PETimeUnit.Millise)
        {
            switch (timeUnit)
            {
                case PETimeUnit.Second:
                    delay = delay * 1000;
                    break;
                case PETimeUnit.Minute:
                    delay = delay * 1000 * 60;
                    break;
                case PETimeUnit.Hour:
                    delay = delay * 1000 * 60 * 60;
                    break;
                case PETimeUnit.Day:
                    delay = delay * 1000 * 60 * 60 * 24;
                    break;
                default:
                    Debug.LogWarning("Time Task Type Is Error...");
                    break;
            }
        }

        int tid = GetId();

        float destTime = Time.realtimeSinceStartup * 1000 + delay;
        mTempTimeTaskList.Add(new PETimeTask(tid, callBack, destTime, delay, count));
        tidList.Add(tid);
        return tid;
    }

    public bool DelectTimeTask(int tid)
    {
        bool exist = false;

        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            if (tid == mTimerTaskList[i].tid)
            {
                mTimerTaskList.RemoveAt(i);
                for (int j = 0; j < tidList.Count; j++)
                {
                    if (tid == tidList[j])
                    {
                        tidList.RemoveAt(j);
                        break;
                    }
                }
                exist = true;
                break;
            }
        }

        if (!exist)
        {
            for (int i = 0; i < mTempTimeTaskList.Count; i++)
            {
                if (tid == mTempTimeTaskList[i].tid)
                {
                    mTempTimeTaskList.RemoveAt(i);
                    for (int j = 0; j < tidList.Count; j++)
                    {
                        if (tid == tidList[j])
                        {
                            tidList.RemoveAt(j);
                            break;
                        }
                    }
                    exist = true;
                    break;
                }
            }
        }

        return exist;
    }

    public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, PETimeUnit timeUnit = PETimeUnit.Millise)
    {
        if (timeUnit != PETimeUnit.Millise)
        {
            switch (timeUnit)
            {
                case PETimeUnit.Second:
                    delay = delay * 1000;
                    break;
                case PETimeUnit.Minute:
                    delay = delay * 1000 * 60;
                    break;
                case PETimeUnit.Hour:
                    delay = delay * 1000 * 60 * 60;
                    break;
                case PETimeUnit.Day:
                    delay = delay * 1000 * 60 * 60 * 24;
                    break;
                default:
                    Debug.LogWarning("Time Task Type Is Error...");
                    break;
            }
        }
        bool isReplace = false;
        float destTime = Time.realtimeSinceStartup * 1000 + delay;
        PETimeTask newTask = new PETimeTask(tid, callBack, destTime, delay, count);

        for (int i = 0; i < mTimerTaskList.Count; i++)
        {
            if (mTimerTaskList[i].tid == tid)
            {
                mTimerTaskList[i] = newTask;
                isReplace = true;
                break;
            }
        }

        if (!isReplace)
        {
            for (int i = 0; i < mTempTimeTaskList.Count; i++)
            {
                if (mTempTimeTaskList[i].tid == tid)
                {
                    mTempTimeTaskList[i] = newTask;
                    isReplace = true;
                    break;
                }
            }
        }
        return isReplace;
    }

    public int GetId()
    {
        //添加计时任务为多线程,多线程生成唯一ID时需要锁防止同时访问生成
        lock (obj)
        {
            tid += 1;

            //安全检测 以防万一
            while (true)
            {
                //tid达到int的最大值时
                if (tid == int.MaxValue)
                {
                    tid = 0;
                }

                bool isUsed = false;

                for (int i = 0; i < tidList.Count; i++)
                {
                    if (tid == tidList[i])
                    {
                        isUsed = true;
                        break;
                    }
                }
                if (!isUsed)
                {
                    break;
                }
                else
                {
                    tid += 1;
                }
            }
        }

        return tid;
    }
}

 

---结束----

 

 

 

 

 

 

你可能感兴趣的:(其他)