Unity 多任务定时器模块

为什么自己做定时器系统

首先我们先来看下,在Unity中可以定时执行的三种方式:

  1. Update
      面对多任务定时器,Update的方式较为麻烦。
  2. 协程
yield return new WaitForSeconds(时间);
yield return new WaitForSecondsRealtime(时间);

  每次启动定时器,都要开启一个协程,若开启协程任务太多,会造成程序卡顿。
  3. Invoke

Invoke("fun",delay); //等待delay秒后调用fun方法
InvokeRepeating("fun",delay,duration); //首次等待delay秒后调用fun方法,以后每隔duration秒调用

  Invoke()方法是 Unity3D 的一种委托机制。Invoke()方法必须输入方法名,对于上下文的引用不便,不能传参。

定时器原理

  开发一个业务模块提供触发接口和处理定时任务,在Update方法里面执行定时任务队列,定时条件满足则执行回调。可以设置定时器的回调方法、回调参数、首次触发延时时间、重复次数和触发时间间隔。

核心代码

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// 读者需要注意两个点:
/// 1.计时任务对象初始化时,将时间间隔赋值给当前时间变量,Update更新时间时,判断当前时间是否大于或等于首次延迟调用+时间间隔的和,能保证首次执行计时按照延迟时间,并在这之后将延迟时间等于0.
/// 2.删除和增加定时器不能直接添加,暂时缓存的集合中,在遍历之前添加到执行任务字典中,遍历结束删除终止的定时器。
/// 3.重复次数等于0,则执行无限计时。
/// </summary>
public class TimerMgr : UnitySIngleton<TimerMgr>
{
    
    
    private Dictionary<int, TimerTask> m_TimerTasks = new Dictionary<int, TimerTask>();
    private List<TimerTask> m_CacheRemoveList = new List<TimerTask>();
    private List<TimerTask> m_CacheAddList = new List<TimerTask>();
    private int TaskID = 0;
    public void Update()
    {
    
    
        //缓存增加任务添加到执行任务字典
        for (int index = 0; index < m_CacheAddList.Count; index++)
        {
    
    
            m_TimerTasks.Add(m_CacheAddList[index].ID, m_CacheAddList[index]);
        }
        m_CacheAddList.Clear();

        for (int index = 0; index < m_TimerTasks.Count; index++)
        {
    
    
            var timerTask = m_TimerTasks.ElementAt(index);
            if(timerTask.Value.IsCanRemove)
            {
    
    
                continue;
            }
            if(timerTask.Value.CurTime < timerTask.Value.Duration + timerTask.Value.DelayTime)
            {
    
    
                timerTask.Value.CurTime += Time.deltaTime;
            }
            else
            {
    
    
                timerTask.Value.Complete?.Invoke(timerTask.Value.Paramt);
                timerTask.Value.CurTime = 0;
                timerTask.Value.DelayTime = 0;
                timerTask.Value.Repeat--;
                
                if(timerTask.Value.Repeat == 0)
                {
    
    
                    m_TimerTasks.Remove(timerTask.Key);
                    //移除会改变执行任务字典,确保执行全部任务
                    index -= 1;
                }
            }
        }
        //移除终止任务对象
        for (int index = 0; index < m_CacheRemoveList.Count; index++)
        {
    
    
            if(m_TimerTasks.ContainsKey(m_CacheRemoveList[index].ID))
            {
    
    
                m_TimerTasks.Remove(m_CacheRemoveList[index].ID);
            }
        }
        m_CacheRemoveList.Clear();
    }
    /// <summary>
    /// 单次定时器(无参)
    /// </summary>
    /// <param name="complete">回调</param>
    /// <param name="delay">延时间隔</param>
    /// <returns></returns>
    public int TimingOnce(Action<object> complete, float delay)
    {
    
    
        return Timing(complete, 1, delay);
    }
    /// <summary>
    /// 单次定时器(有参)
    /// </summary>
    /// <param name="complete">回调</param>
    /// <param name="paramt">参数</param>
    /// <param name="delay">延时间隔</param>
    /// <returns></returns>
    public int TimingOnce(Action<object> complete,object paramt ,float delay)
    {
    
    
        return Timing(complete, paramt, 1, delay);
    }
    /// <summary>
    /// 重复定时器(无参)
    /// </summary>
    /// <param name="complete">回调函数</param>
    /// <param name="repeat">重复次数</param>
    /// <param name="duration">时间间隔</param>
    /// <param name="delay">延时</param>
    /// <returns></returns>
    public int Timing(Action<object> complete, int repeat, float delay, float duration = 0)
    {
    
    
        return Timing(complete, null, repeat, delay, duration);
    }
    /// <summary>
    /// 重复定时器(有参)
    /// </summary>
    /// <param name="complete">回调</param>
    /// <param name="paramt">回调参数</param>
    /// <param name="repeat">重复次数</param>
    /// <param name="duration">计时间隔</param>
    /// <param name="delay">开始延时间隔</param>
    /// <returns></returns>
    public int Timing(Action<object> complete, object paramt, int repeat, float delay, float duration = 0)
    {
    
    
        TaskID++;
        TimerTask timerTask = new TimerTask();
        timerTask.Complete = complete;
        timerTask.Paramt = paramt;
        timerTask.Repeat = repeat;
        timerTask.Duration = duration;
        timerTask.DelayTime = delay;
        timerTask.CurTime = duration;
        timerTask.ID = TaskID;
        timerTask.IsCanRemove = false;
        m_CacheAddList.Add(timerTask);
        return TaskID;
    }
    /// <summary>
    /// 停止计时
    /// </summary>
    /// <param name="id"></param>
    public void StopTiming(int id)
    {
    
    
        if (!m_TimerTasks.ContainsKey(id))
            return;
        m_TimerTasks[id].IsCanRemove = true;
        m_CacheRemoveList.Add(m_TimerTasks[id]);
    }
}
public class TimerTask
{
    
    
    public int ID;
    public Action<object> Complete;
    public object Paramt;
    public float Duration;
    public float DelayTime;
    public float CurTime;
    public int Repeat;
    public bool IsCanRemove;
}

测试

在这里插入图片描述
在这里插入图片描述

おすすめ

転載: blog.csdn.net/weixin_42186644/article/details/120194145