网页链接:https://devpress.csdn.net/guangzhou/649ed8f88501cb0bc4b12899.html

 

1. 不使用定时任务系统的定时器实现

1.1 Time.deltaTime

using UnityEngine;

public class Test : MonoBehaviour
{
    public float timer = 0f; 
    
    void Update()
    {
        timer += Time.deltaTime;
        if (timer >= 2)
        {
            doSomething();
            timer = 0f; // 定时2秒
        }
    }

    void doSomething()
    {
        Debug.Log("每2秒执行一次");
    }
}

1.2 Time.time

using UnityEngine;

public class Test : MonoBehaviour
{
    public float timer = 0f;

    void Start()
    {
        timer = Time.time;
    }

    void Update()
    {
        timer += Time.deltaTime;
        if (Time.time - timer >= 2)// 定时2秒
        {
            doSomething();
            timer = Time.time; 
        }
    }

    void doSomething()
    {
        Debug.Log("每2秒执行一次");
    }
}

1.3 使用延迟调用函数

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        //0秒后,每2秒执行一次doSomething
        InvokeRepeating("doSomething", 0, 2);
    }

    void doSomething()
    {
        Debug.Log("每2秒执行一次");
    }
}

1.4 使用协程

using System;
using System.Collections;
using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        //每2秒执行一次doSomething
        StartCoroutine(UpdateTimer(2f, doSomething));
    }

    void doSomething()
    {
        Debug.Log("每2秒执行一次");
    }

    IEnumerator UpdateTimer(float timer,Action callBack)
    {
        var wait = new WaitForSeconds(timer);
        while (true)
        {
            yield return wait;
            callBack();
        }
    }
}

2. 简易定时任务

定时任务类:

/*
 * FileName:    PETimeTask
 * Author:      ming
 * CreateTime:  2023/6/29 18:27:54
 * Description: 定时任务
 * 
*/

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
}

简易定时任务系统:

/*
 * FileName:    TimerSystemSimple
 * Author:      ming
 * CreateTime:  2023/6/29 18:26:36
 * Description: 简易定时任务系统
 * 
*/

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

public class TimerSystemSimple : MonoBehaviour
{
    private int tid = 0;    // 全局任务 id

    public static TimerSystemSimple _instance;
    // 任务列表
    private List<PETimeTask> mTimerTaskList = new List<PETimeTask>();

    void Awake() 
    {
        _instance = this;
    }

    private void Update() 
    {
        for (int i = 0; i < mTimerTaskList.Count; i++) 
        {
            PETimeTask timeTask = mTimerTaskList[i];
            // 任务已经到达执行时间
            if (timeTask.destTime <= Time.realtimeSinceStartup * 1000) 
            {
                if (timeTask.callBack != null) timeTask.callBack();
                // 移除已经完成的任务
                if (timeTask.count == 1) 
                {
                    mTimerTaskList.RemoveAt(i);
                    i--;
                }
                else 
                {
                    if (timeTask.count != 0) 
                    {
                        timeTask.count -= 1;
                    }
                    timeTask.destTime += timeTask.delay;
                }
            }
        }
    }

    /*
    * callback:     回调
    * delay:        延迟执行时间 
    * count:        执行次数,0--循环执行
    * PETimeUnit:   时间单位,默认为秒
    * return:       返回任务唯一id
    */
    public int AddTimeTask(Action callback, float delay, int count = 1, PETimeUnit timeUnit = PETimeUnit.Second) {
        // 转换时间格式
        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;
            }
        }

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

    /*
    * tid:          任务唯一id
    * return:       移除成功返回true,不存在返回false
    */
    public bool RemoveTimeTask(int tid)
    {
        bool exist = false;
        for (int i = 0; i < mTimerTaskList.Count; i++) {
            if (tid == mTimerTaskList[i].tid)
            {
                mTimerTaskList.RemoveAt(i);
                exist = true;
            }
        }
        return exist;
    }

    public bool ReplaceTimeTask(int tid, Action callback, float delay, int count = 1, PETimeUnit timeUnit = PETimeUnit.Second) 
    {
        // 转换时间格式
        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;
        for (int i = 0; i < mTimerTaskList.Count; i++) 
        {
            if(tid == mTimerTaskList[i].tid)
            {
                // 生成新的定时任务
                float destTime = Time.realtimeSinceStartup * 1000 + delay;
                PETimeTask newTask = new PETimeTask(tid, callback, destTime, delay, count);
                
                mTimerTaskList[i] = newTask;
                isReplace = true;
                break;
            }
        }
        return isReplace;
    }
}

3. 更为完善的定时任务系统

/*
 * FileName:    TimerSystem
 * Author:      ming
 * CreateTime:  2023/6/29 18:26:36
 * Description: 定时任务系统
 * 
*/

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<PETimeTask> mTimerTaskList = new List<PETimeTask>();
 
    // 临时缓存列表
    private List<PETimeTask> mTempTimeTaskList = new List<PETimeTask>();
 
    // 存储tid
    private List<int> tidList = new List<int>();
 
    // 存储需清理的ID
    private List<int> recIDList = new List<int>();
 
    private void Awake()
    {
        _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 AddTimeTask(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;
    }
}