基于Unity的定时器封装

基于Unity的定时器封装

一.封装原因:

在unity中有多种方法能实现定时器的效果,比如在Update中累加Time.deltaTime,或者是通过Time.time,亦或者通过协程yield return new WaitForSeconds()来实现,这些方法十分简单,在代码简洁时还能应付过来,当代码数量多了时,这些方法就会显得过于冗杂,这时就需要一个定时器系统来管理这些定时的任务。

二.代码实现:

1.整体类结构

在这里插入图片描述
(1.图中的TimerTask类是定时的任务
(2.图中的TimeSys类是管理Time的系统
(3.图中的TimeTest类用来测试

2.TimerTask具体内容

TimerTask是关于时间定时的任务
FrameTask是关于帧定时的任务
TimeType是时间定时的时间单位

using UnityEngine;
using System;

public class TimerTask
{
    public Action callback;
    public float bsetTime;
    public int currNum;
    public float delayTime;
    public int tID;
}
public class FrameTask
{
    public Action callback;
    public int bsetTime;
    public int currNum;
    public int delayTime;
    public int tID;
}
public enum TimeType
{
    Millisecond,
    Second,
    Minute,
    Hour,
    Day
}
3.TimeSys具体实现

用两个列表来存储各自的任务
还有一个tIDs列表来存储任务对应的ID
tID用来存储当前的任务ID,以便每次添加定时任务时给定时任务唯一的ID
lock是为了防止在多线程中对tID进行改变
frame是用来记录游戏开始到现在的帧数

-----------------------------------------方法说明-----------------------------------------------

TimeFunc和FrameFunc都是在Update中判断当前的时间或帧数是否满足任务执行需要的帧数(类似于Time.time计时器方法)

Add,Del,RepTimeTask分别为添加定时任务,删除定时任务,替换定时任务(下面的帧相关的3个方法同理)

GetTID是用来生成任务唯一的ID号
在这里插入图片描述

下面为TimeSys完整代码
using System.Collections.Generic;
using UnityEngine;
using System;

public class TimeSys : MonoBehaviour
{
    private static TimeSys instance;
    public static TimeSys Instance
    {
        get
        {
            if (instance == null)
            {
                instance = GameObject.FindObjectOfType<TimeSys>();
            }
            return instance;
        }
        set
        {
            if (instance == null)
            {
                instance = value;
            }
        }
    }
    public void Start()
    {
        Instance = this;
    }
    private List<TimerTask> timerTasks = new List<TimerTask>();
    private List<FrameTask> frameTasks = new List<FrameTask>();
    private List<int> tIDs = new List<int>();
    private int tID;
    private static readonly string obj = "lock";
    private int frame;

    private void Update()
    {
        frame++;
        TimeFunc();
        FrameFunc();
    }

    private void TimeFunc()
    {
        for (int i = 0; i < timerTasks.Count; i++)
        {
            if (timerTasks[i].bsetTime < Time.realtimeSinceStartup * 1000)
            {
                if (timerTasks[i].callback != null)
                {
                    timerTasks[i].callback();
                    timerTasks[i].bsetTime = Time.realtimeSinceStartup * 1000f + timerTasks[i].delayTime;
                    if (timerTasks[i].currNum == -1)
                    {
                        continue;
                    }
                    else
                    {
                        timerTasks[i].currNum--;
                        if (timerTasks[i].currNum == 0)
                        {
                            timerTasks.RemoveAt(i);
                            i--;
                        }
                    }
                }
            }
        }
    }

    private void FrameFunc()
    {
        for (int i = 0; i < frameTasks.Count; i++)
        {
            if (frameTasks[i].bsetTime < frame)
            {
                if (frameTasks[i].callback != null)
                {
                    frameTasks[i].callback();
                    frameTasks[i].bsetTime = frame + frameTasks[i].delayTime;
                    if (frameTasks[i].currNum == -1)
                    {
                        continue;
                    }
                    else
                    {
                        frameTasks[i].currNum--;
                        if (frameTasks[i].currNum == 0)
                        {
                            frameTasks.RemoveAt(i);
                            i--;
                        }
                    }
                }
            }
        }
    }

    #region 时间相关
    /// <summary>
    /// 
    /// </summary>
    /// <param name="delayTime"></param>
    /// <param name="action"></param>
    /// <param name="timeType"></param>
    /// <param name="num">-1为无限循环,其余整数为循环次数</param>
    public int AddTimerTask(float delayTime, Action action, TimeType timeType = TimeType.Millisecond, int num = 1)
    {
        if (timeType != TimeType.Millisecond)
        {
            switch (timeType)
            {
                case TimeType.Second:
                    delayTime *= 1000;
                    break;
                case TimeType.Minute:
                    delayTime *= 60;
                    break;
                case TimeType.Hour:
                    delayTime *= 3600;
                    break;
                case TimeType.Day:
                    delayTime *= (3600 * 24);
                    break;
                default:
                    break;
            }
        }
        int id = GetTID();
        TimerTask timerTask = new TimerTask { bsetTime = Time.realtimeSinceStartup * 1000f + delayTime, callback = action, currNum = num, delayTime = delayTime };
        timerTask.tID = id;
        timerTasks.Add(timerTask);
        tIDs.Add(id);
        return timerTask.tID;
    }

    public bool DelTimerTask(int tID)
    {
        bool isSucced = false;
        for (int i = 0; i < timerTasks.Count; i++)
        {
            if (timerTasks[i].tID == tID)
            {
                timerTasks.RemoveAt(i);
                isSucced = true;
                tIDs.Remove(tID);
                break;
            }
        }
        return isSucced;
    }

    public bool RepTimerTask(int tID, float delayTime, Action action, TimeType timeType = TimeType.Millisecond, int num = 1)
    {
        bool isSucced = false;
        for (int i = 0; i < timerTasks.Count; i++)
        {
            if (timerTasks[i].tID == tID)
            {
                if (timeType != TimeType.Millisecond)
                {
                    switch (timeType)
                    {
                        case TimeType.Second:
                            delayTime *= 1000;
                            break;
                        case TimeType.Minute:
                            delayTime *= 60;
                            break;
                        case TimeType.Hour:
                            delayTime *= 3600;
                            break;
                        case TimeType.Day:
                            delayTime *= (3600 * 24);
                            break;
                        default:
                            break;
                    }
                }
                TimerTask timerTask = new TimerTask { bsetTime = Time.realtimeSinceStartup * 1000f + delayTime, callback = action, currNum = num, delayTime = delayTime };
                timerTask.tID = GetTID();
                timerTasks[i] = timerTask;
                isSucced = true;
            }
        }
        return isSucced;
    }
    #endregion



    #region 帧相关

    public int AddFrameTimerTask(int delayTime, Action action, int num = 1)
    {
        int id = GetTID();
        FrameTask timerTask = new FrameTask { bsetTime = frame + delayTime, callback = action, currNum = num, delayTime = delayTime };
        timerTask.tID = id;
        frameTasks.Add(timerTask);
        tIDs.Add(id);
        return timerTask.tID;
    }

    public bool DelFrameTimerTask(int tID)
    {
        bool isSucced = false;
        for (int i = 0; i < frameTasks.Count; i++)
        {
            if (frameTasks[i].tID == tID)
            {
                frameTasks.RemoveAt(i);
                isSucced = true;
                tIDs.Remove(tID);
                break;
            }
        }
        return isSucced;
    }

    public bool RepFrameTimerTask(int tID, int delayTime, Action action, int num = 1)
    {
        bool isSucced = false;
        for (int i = 0; i < frameTasks.Count; i++)
        {
            FrameTask timerTask = new FrameTask { bsetTime = frame + delayTime, callback = action, currNum = num, delayTime = delayTime };
            timerTask.tID = GetTID();
            frameTasks[i] = timerTask;
            isSucced = true;
        }
        return isSucced;
    }
    #endregion

    #region 通用生成ID
    private int GetTID()
    {
        lock (obj)
        {
            tID++;

            while (true)
            {
                if (tID == int.MaxValue)
                {
                    tID = 0;
                }
                bool used = false;
                for (int i = 0; i < tIDs.Count; i++)
                {
                    if (tIDs[i] == tID)
                    {
                        used = true;
                        break;
                    }
                }
                if (!used)
                {
                    break;
                }
                tID++;
            }
        }
        return tID;

    }
    #endregion
}
最后测试一下定时器
public class TimeTest : MonoBehaviour
{
    private int tID;
    private void Start()
    {
        tID = TimeSys.Instance.AddFrameTimerTask(1, SayHello,-1);
    }
    private void SayHello()
    {
        Debug.Log("Hello");
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            TimeSys.Instance.RepFrameTimerTask(tID, 200, () => Debug.Log("Over..."), 5);
        }
    }
}

运行后unity每1帧打印一条“Hello”,当我按下空格时,每过200帧打印一句Over…,一共打印了5次。
这样一个计时器的封装就完成了!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值