首先来尝试MonoBehaviour类

首先新建一个PERrame 和PETime 按时间和按帧统计类

using System;
using UnityEngine;
public class PEFrameTask
{
    public int tid;//全局唯一的ID
    public Action callBack;//执行方法
    public int dastFrame; //目标帧
    public int delay;  //延迟时间
    public int count;//执行次数  0 是死循环

    public PEFrameTask(int tid, Action callBack, int dastFrame, int delay, int count)
    {
        this.tid = tid;
        this.callBack = callBack;
        this.dastFrame = dastFrame;
        this.delay = delay;
        this.count = count;
    }
}public class PETimeTask
{
    public int tid;//全局唯一的ID
    public Action callBack;//执行方法
    public double dastTime; //单位是毫秒
    public float delay;  //延迟时间
    public int count;//执行次数  0 是死循环

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

public enum PETimeUnit
{
    Millisecond, //毫秒
    Second,//秒
    Minute,//分钟
    Hour,//小时
    Day,//天
}

然后新建PETimer核心类

using System;
using System.Collections.Generic;

public class PETimer
{
    private DateTime startDateTime = new DateTime(1070, 1, 1, 0, 0, 0);
    private Action<string> taskLog;
    private static readonly string obj = "lock";
    private double nowTime;
    private int tid;
    private List<PETimeTask> tempTimeList = new List<PETimeTask>();
    private List<PETimeTask> taskTimeList = new List<PETimeTask>();
    private List<int> recTidList = new List<int>();
    private List<int> tidList = new List<int>();
    private List<PEFrameTask> tempFrameList = new List<PEFrameTask>();
    private List<PEFrameTask> taskFrameList = new List<PEFrameTask>();
    private int frameCounter;  //当前帧
    public PETimer()
    {
        taskFrameList.Clear();
        tempFrameList.Clear();
        tidList.Clear();
        recTidList.Clear();
        taskTimeList.Clear();
        tempTimeList.Clear();
    }
    public void SetLog(Action<string> log)
    {
        taskLog = log;
    }
    public void LogInfo(string info)
    {
        if (taskLog != null)
        {
            taskLog(info);
        }
    }
    public void Update()
    {
        CheckTimeTask();
        CheckFrameTask();
        if (recTidList.Count > 0)
        {
            RecycleTid();
        }
    }
    #region TimeTask
    public void CheckTimeTask()
    {
        //加入缓存区中的定时任务
        for (int i = 0; i < tempTimeList.Count; i++)
        {
            taskTimeList.Add(tempTimeList[i]);
        }
        tempTimeList.Clear();
        nowTime = GetUTCMillisecoonds();
        for (int index = 0; index < taskTimeList.Count; index++)
        {
            PETimeTask task = taskTimeList[index];
            if (nowTime.CompareTo(task.dastTime)< 0)
            {
                continue;
            }
            else
            {
                Action cb = task.callBack;
                try
                {
                    if (cb != null)
                    {
                        cb();
                    }
                }
                catch (Exception e)
                {
                    LogInfo(e.ToString());
                }
                if (task.count == 1)
                {
                    //移除已完成的任务
                    taskTimeList.RemoveAt(index);
                    //移除以后  索引向下移动一位
                    index--;
                    recTidList.Add(task.tid);
                }
                else
                {
                    if (task.count != 0)
                    {
                        task.count -= 1;
                    }
                    task.dastTime += task.delay;
                }

            }
        }

    }
    public int AddTimeTask(Action callBack, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1)
    {
        if (timeUnit != PETimeUnit.Millisecond)
        {
            switch (timeUnit)
            {
                case PETimeUnit.Day:
                    delay = delay * 1000 * 60 * 60 * 24;
                    break;
                case PETimeUnit.Hour:
                    delay = delay * 1000 * 60 * 60;
                    break;
                case PETimeUnit.Minute:
                    delay = delay * 1000;
                    break;
                case PETimeUnit.Second:
                    delay = delay * 1000 * 60;
                    break;
                default:
                    LogInfo("Add task TimeUnit Type Error... ");
                    break;
            }
        }
        //从启动游戏的时间 + 延迟时间
        double destTime = GetUTCMillisecoonds() + delay;

        int tid = GetTid();
        tempTimeList.Add(new PETimeTask(tid, callBack, destTime, delay, count));
        tidList.Add(tid);
        LogInfo("Add Time Task");
        return tid;
    }
    public bool DelTimeTask(int tid)
    {
        bool exist = false;
        for (int i = 0; i < taskTimeList.Count; i++)
        {
            PETimeTask task = taskTimeList[i];
            if (task.tid == tid)
            {
                taskTimeList.RemoveAt(i);
                for (int j = 0; j < tidList.Count; j++)
                {
                    if (tidList[i] == tid)
                    {
                        tidList.RemoveAt(j);
                        break;
                    }
                }
                exist = true;
                break;
            }
        }
        if (!exist)
        {
            for (int i = 0; i < tempTimeList.Count; i++)
            {
                PETimeTask task = tempTimeList[i];
                if (task.tid == tid)
                {
                    tempTimeList.RemoveAt(i);
                    for (int j = 0; j < tidList.Count; j++)
                    {
                        if (tidList[i] == tid)
                        {
                            tidList.RemoveAt(j);
                            break;
                        }
                    }
                    exist = true;
                    break;
                }
            }
        }
        return exist;
    }
    public bool ReplaceTimeTask(int tid, Action callBack, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1)
    {

        if (timeUnit != PETimeUnit.Millisecond)
        {
            switch (timeUnit)
            {
                case PETimeUnit.Day:
                    delay = delay * 1000 * 60 * 60 * 24;
                    break;
                case PETimeUnit.Hour:
                    delay = delay * 1000 * 60 * 60;
                    break;
                case PETimeUnit.Minute:
                    delay = delay * 1000;
                    break;
                case PETimeUnit.Second:
                    delay = delay * 1000 * 60;
                    break;
                default:
                    LogInfo("Add task TimeUnit Type Error... ");
                    break;
            }
        }
        //从启动游戏的时间 + 延迟时间
        double destTime = GetUTCMillisecoonds() + delay;
        PETimeTask newTask = new PETimeTask(tid, callBack, destTime, delay, count);
        bool exist = false;
        for (int i = 0; i < taskTimeList.Count; i++)
        {
            PETimeTask task = taskTimeList[i];
            if (task.tid == tid)
            {
                taskTimeList[i] = newTask;
                exist = true;
                break;
            }
        }
        if (!exist)
        {
            for (int i = 0; i < tempTimeList.Count; i++)
            {
                PETimeTask task = tempTimeList[i];
                if (task.tid == tid)
                {
                    tempTimeList[i] = newTask;
                    exist = true;
                    break;
                }
            }
        }

        return exist;
    }
    #endregion
    #region  FrameTask
    public void CheckFrameTask()
    {
        //加入缓存区中的定时任务
        for (int i = 0; i < tempFrameList.Count; i++)
        {
            taskFrameList.Add(tempFrameList[i]);
        }
        tempFrameList.Clear();
        frameCounter += 1;
        for (int index = 0; index < taskFrameList.Count; index++)
        {
            PEFrameTask task = taskFrameList[index];
            if (frameCounter < task.dastFrame)
            {
                continue;
            }
            else
            {
                Action cb = task.callBack;
                try
                {
                    if (cb != null)
                    {
                        cb();
                    }
                }
                catch (Exception e)
                {
                    LogInfo(e.ToString());
                }
                if (task.count == 1)
                {
                    //移除已完成的任务
                    taskFrameList.RemoveAt(index);
                    //移除以后  索引向下移动一位
                    index--;
                    recTidList.Add(task.tid);
                }
                else
                {
                    if (task.count != 0)
                    {
                        task.count -= 1;
                    }
                    task.dastFrame += task.delay;
                }
            }
        }
    }
    public int AddFrameTask(Action callBack, int delay, int count = 1)
    {
        int tid = GetTid();
        tempFrameList.Add(new PEFrameTask(tid, callBack, frameCounter + delay, delay, count));
        tidList.Add(tid);
        LogInfo("Add Time Task");
        return tid;
    }
    public bool DelFrameTask(int tid)
    {
        bool exist = false;
        for (int i = 0; i < taskFrameList.Count; i++)
        {
            PEFrameTask task = taskFrameList[i];
            if (task.tid == tid)
            {
                taskFrameList.RemoveAt(i);
                for (int j = 0; j < tidList.Count; j++)
                {
                    if (tidList[i] == tid)
                    {
                        tidList.RemoveAt(j);
                        break;
                    }
                }
                exist = true;
                break;
            }
        }
        if (!exist)
        {
            for (int i = 0; i < tempFrameList.Count; i++)
            {
                PEFrameTask task = tempFrameList[i];
                if (task.tid == tid)
                {
                    tempFrameList.RemoveAt(i);
                    for (int j = 0; j < tidList.Count; j++)
                    {
                        if (tidList[i] == tid)
                        {
                            tidList.RemoveAt(j);
                            break;
                        }
                    }
                    exist = true;
                    break;
                }
            }
        }
        return exist;
    }
    public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)
    {

        PEFrameTask newTask = new PEFrameTask(tid, callBack, frameCounter + delay, delay, count);
        bool exist = false;
        for (int i = 0; i < taskFrameList.Count; i++)
        {
            PEFrameTask task = taskFrameList[i];
            if (task.tid == tid)
            {
                taskFrameList[i] = newTask;
                exist = true;
                break;
            }
        }
        if (!exist)
        {
            for (int i = 0; i < tempTimeList.Count; i++)
            {
                PETimeTask task = tempTimeList[i];
                if (task.tid == tid)
                {
                    tempFrameList[i] = newTask;
                    exist = true;
                    break;
                }
            }
        }

        return exist;
    }

    #endregion
    #region Tool Methonds
    //回收ID
    public void RecycleTid()
    {
        for (int i = 0; i < recTidList.Count; i++)
        {
            int tid = recTidList[i];
            for (int j = 0; j < tidList.Count; j++)
            {
                if (tidList[j] == tid)
                {
                    //删除tidList中的数据
                    tidList.RemoveAt(j);
                    break;
                }
            }
        }
        recTidList.Clear();
    }
    private int GetTid()
    {
        lock (obj)
        {
            tid += 1;

            while (true)
            {
                //安全代码以防万一
                if (tid == int.MaxValue)
                {
                    tid = 0;
                }
                bool used = false;
                for (int i = 0; i < tidList.Count; i++)
                {
                    if (tid == tidList[i])
                    {
                        used = true;
                        break;
                    }
                }
                if (!used)
                {
                    break;
                }
                else
                {
                    tid += 1;
                }
            }
        }
        return tid;
    }
    private double GetUTCMillisecoonds()
    {
        //  DateTime.UtcNow 世界标准时间
        TimeSpan ts = DateTime.UtcNow - startDateTime;
        //计算元年 到现在的毫秒数?
        return ts.TotalMilliseconds;
    }
    #endregion




}

添加扩展类 添加计时器和方法

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///计时器系统
//开发目标
//支持时间的定时,帧定时
//定时任务可循环,可取消 可替换
//使用简单 调用方便
public class TimerSystem : MonoBehaviour
{
    public static TimerSystem Instance;

    public PETimer pt;
    public void InitSystem()
    {
        Instance = this;
        pt = new PETimer();
        pt.SetLog((string info) =>
        {
            Debug.Log("PETimerLog:" + info);
        });
        Debug.Log("TimerSys Init Done.");
    }

    void Update()
    {
        pt.Update();
    }
    #region TimeTask
    private void CheckTimeTask()
    {
        pt.CheckTimeTask();
    }
    public int AddTimeTask(Action callBack, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1)
    {
        return pt.AddTimeTask(callBack, delay, timeUnit, count);
    }
    public bool DelTimeTask(int tid)
    {
        return pt.DelTimeTask(tid);
    }
    public bool ReplaceTimeTask(int tid, Action callBack, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1)
    {
        return pt.ReplaceTimeTask(tid, callBack, delay, timeUnit, count);
    }
    #endregion
    #region  FrameTask
    public void CheckFrameTask()
    {
        pt.CheckFrameTask();
    }
    public int AddFrameTask(Action callBack, int delay, int count = 1)
    {
        return pt.AddFrameTask(callBack, delay, count);
    }
    public bool DelFrameTask(int tid)
    {
        return pt.DelFrameTask(tid);
    }
    public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)
    {
        return pt.ReplaceFrameTask(tid, callBack, delay, count);
    }
    #endregion
}

Test演示类  添加删除替换计时器

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

public class GameRoot : MonoBehaviour
{
    TimerSystem timerSystem;
    private void Start()
    {
        timerSystem = GetComponent<TimerSystem>();
        timerSystem.InitSystem();
    }
    private int tid;
    public void ClickAddButton()
    {
        tid = TimerSystem.Instance.AddTimeTask(() =>
        {
            Debug.Log(" debug " + " log A " + " Id : " + tid + "Now " + System.DateTime.Now);
        }, 500, PETimeUnit.Millisecond, 0);
    }
    public void ClickDelButton()
    {
        bool IsDelete = TimerSystem.Instance.DelTimeTask(tid);
        Debug.Log("删除" + IsDelete + " 删除的ID为: " + tid);
    }
    public void ClickRepButton()
    {
        bool IsDelete = TimerSystem.Instance.ReplaceTimeTask(tid, FuncB, 2000, PETimeUnit.Millisecond, 0);
        Debug.Log("替换任务" + IsDelete + " 替换的ID为: " + tid);
    }
    void FuncA()
    {
        Debug.Log(" debug " + " log A " + " Id : " + tid);
    }
    void FuncB()
    {
        Debug.Log(" debug " + " log B " + " Id : " + tid);
    }
    public void ClickAddFrameButton()
    {
        tid = TimerSystem.Instance.AddFrameTask(() =>
        {
            Debug.Log(" debug " + " log A " + " Id : " + tid + "Now " + System.DateTime.Now);
        }, 60, 0);
    }
    public void ClickDelFrameButton()
    {
        bool IsDelete = TimerSystem.Instance.DelFrameTask(tid);
        Debug.Log("删除" + IsDelete + " 删除的ID为: " + tid);
    }
    public void ClickRepReameButton()
    {
        bool IsDelete = TimerSystem.Instance.ReplaceFrameTask(tid, FuncB, 100, 0);
        Debug.Log("替换任务" + IsDelete + " 替换的ID为: " + tid);
    }



}

如果是脱离MonoBehaviour的话 可以开启线程然后死循环  自己可以修改 并不复杂哦