Unity3d通用工具類之定時觸發器


時隔多日,好不容易擠出點時間來寫寫博文。不容易,請送我幾朵紅花,點個贊也行。

 

今天呢,我們主要來擴展下通用工具類==>定時觸發器。

 

顧名思義,所謂的定時觸發器,就是告訴程序在過多長時間后,我要執行某個特定的任務。

 

比如舉個小栗子:

電飯煲,相信大家都用過,當我們出去工作或者上學的時候,我們只要設置下煮飯時間,就可以安心的離開。

 

電飯煲會自動的開始計時工作,等到了你設置的時間后,他就會自動的開始煮飯啊什么的。而你卻可以在遠在千里的上班。

 

智能化,對就是這樣的效果。我們今天就來寫寫這個智能的小東西。

 

首先在設計這個小功能之前,我們要明白自己需要的是什么?如何設計?

 

1.需要什么:

(1)肯定要有個管理定時器的類,命名TimeTaskManager。(上網查了下定時器英文可以為:TimeTask,所以就取了這個名字)

(2)既然有了這個管理類,那么這個管理類要管理什么東西?對嘍,是你所要定時執行的任務。那么這個任務要包含什么東西?

    1.多久時間開始執行任務肯定要,

    2.重復執行間隔(有些任務要定時的重復執行,比如像機器加工廠的機器晝夜重復一個加工動作)

ok,我們命名為TimeTask

 

2.如何設計:

當我們設計一個個有相關聯的類的時候,我們可能需要紙筆來打草稿,其實完全不用,學過uml的同學可以新手拈來。這里呢我推薦使用Process On這個工具。在線繪畫工具,非常好用。

這里我們邊設計邊畫圖:

首先從TimeTask下手,對於這個類,我們要想作為一個任務,而且還是定時的。那么一下就能想到,任務執行用委托。還有程序肯定有許多任務,所以要定義一個id識別這個唯一任務。

那么定時肯定也需要一些變量,

  1.private uint id;//任務id

  2.private uint interval;//間隔多少秒,重復這個任務

  3.private Action action;//無參委托

看到這里,這個Timetask任務類,大致建立好了。

 

哎!細心的同學可能會發現,這個Action委托是個無參委托,那么假如說我的任務方法有帶參的怎么辦呢?哎,那么問題就來了。

 

那么我再設計一個帶一個參數的Timetask<T>類,然后Action<T> action不就行了。那二個參數呢,三個參數呢......?

 

有多少個參數,你都要設計多少個類。

 

所以,對於這樣的情況,我們需要把Timetask抽象成一個基類,命名為AbstractTimeTask

 

 

哎!只要我們所有無參帶參的TimeTask都繼承與AbstractTimeTask抽象類,這樣代碼的復用性就大大提高了。

設計好了之后,我們編寫代碼:

 

 

AbstractTimeTask:

using UnityEngine;
using System.Collections;
using System;
#region 模塊信息
/*----------------------------------------------------------------
// 模塊名:AbstractTimeT
// 創建者:chen
// 修改者列表:
// 創建日期:2015.11.5
// 模塊描述//----------------------------------------------------------------*/
#endregion
public abstract class AbstractTimeTask
{
	#region 字段
    private uint m_uiTimeId;//任務id
    private int m_iInterval;//任務重復時間間隔,為0不重復
    private ulong m_ulNextTick;//下一次觸發的時間點
	#endregion
	#region 屬性
    public uint TimeId
    {
        get 
        {
            return m_uiTimeId;
        }
        set 
        {
            m_uiTimeId = value;
        }
    }
    public int Interval 
    {
        get { return m_iInterval; }
        set { m_iInterval = value; }
    }
    public ulong NextTick 
    {
        get
        {
            return m_ulNextTick;
        }
        set 
        {
            this.m_ulNextTick = value;
        }
    }
    /// <summary>
    /// 抽象屬性,給子類自定義自己的action委托
    /// </summary>
    public abstract Action Action
    {
        get;
        set;
    }
	#endregion
	#region 公有方法
    /// <summary>
    /// 抽象方法,給自己自己定義執行委托
    /// </summary>
    public abstract void DoAction();
	#endregion
}

TimeTask:(這里主要先講無參)

using UnityEngine;
using System.Collections;
using System;
#region 模塊信息
/*----------------------------------------------------------------
// 模塊名:TimeTask
// 創建者:chen
// 修改者列表:
// 創建日期:2015.11.5
// 模塊描述:定時觸發任務類
//----------------------------------------------------------------*/
#endregion
public class TimeTask : AbstractTimeTask
{
	#region 字段
    private Action m_action;//定義自己的委托
	#endregion
	#region 屬性
    public override Action Action
    {
        get
        {
            return m_action;
        }
        set
        {
            m_action = value;
        }
    }
	#endregion
	#region 公有方法
    /// <summary>
    /// 重新父類的委托方法
    /// </summary>
    public override void DoAction()
    {
        m_action();
    }
	#endregion
}

  

這里我們增加了NextTick字段,有什么卵用呢?主要是用來與當前程序運行時間比較,如果剛好等於這個NextTick值時,就觸發委托函數,執行任務。

細想一下,我們定時管理器類要把任務一個個加到隊列里面管理,那么肯定需要一個時間變量與task里面的時間變量進行比較。

所以,定時管理類就需要一個static uint tick變量來記錄程序運行總的時間,如果吧task加到隊列里面,task的NextTick=程序運行的總的時間tick+start(多久之后執行任務);還有就是如果task的interval的值大於0,也就是說有重復的執行,那么,就需要再加上interval的值,然后再加入到隊列里面。

分析了這么多,接着來寫管理類:

TimeTaskManager:

using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;
using System;
#region 模塊信息
/*----------------------------------------------------------------
// 模塊名:TimeTaskManager
// 創建者:chen
// 修改者列表:
// 創建日期:2015.11.5
// 模塊描述:定時觸發器管理類
//----------------------------------------------------------------*/
#endregion
public class TimeTaskManager 
{
	#region 字段
    private static uint m_uiNextTimeId;//總的id,需要分配給task,也就是每加如一個task,就自增
    private static uint m_uiTick;//總的時間,用來和task里面的nexttick變量來進行比較,看是否要觸發任務
    private static Queue<AbstractTimeTask> m_queue;
    private static Stopwatch m_stopWatch;//c#自帶的計時器,不會的自行百度
    private static readonly object m_queueLock = new object();//隊列鎖
	#endregion
	#region 構造方法
    private TimeTaskManager()
    {
 
    }
    static TimeTaskManager()
    {
        m_queue = new Queue<AbstractTimeTask>();
        m_stopWatch = new Stopwatch();
    }
	#endregion
	#region 公有方法
    /// <summary>
    /// 吧Task加入到隊列里面來管理,既然是個管理器肯定要有個添加task的操作
    /// </summary>
    /// <param name="start">多久之后開始執行ms</param>
    /// <param name="interval">重復時間間隔ms</param>
    /// <param name="action">任務委托</param>
    /// <returns>任務id</returns>
    public static uint AddTimer(uint start, int interval, Action action)
    {
        AbstractTimeTask task = GetTimeTask(new TimeTask(), start, interval, action);
        lock (m_queueLock)
        {
            m_queue.Enqueue(task);
        }
        return task.TimeId;
    }
    /// <summary>
    /// 周期性執行
    /// </summary>
    public static void Tick()
    {
        TimeTaskManager.m_uiTick += (uint)(m_stopWatch.ElapsedMilliseconds);
        //nityEngine.Debug.Log(TimeTaskManager.m_uiTick);
        m_stopWatch.Reset();
        m_stopWatch.Start();
        while (m_queue.Count != 0)
        {
            AbstractTimeTask task;
            lock (m_queueLock)
            {
                task = m_queue.Peek();//這里注意隊列並沒有刪除元素,只是放回元素,元素還在隊列里面
            }
            if (TimeTaskManager.m_uiTick < task.NextTick)//如果程序的總時間小於task要執行的時間點,就break點,繼續等待
            {
                break;
            }
            lock (m_queueLock)
            {
                m_queue.Dequeue();
            }
            if (task.Interval > 0)//如果需要重復的話
            {
                task.NextTick += (ulong)task.Interval;
                lock (m_queueLock)
                {
                    m_queue.Enqueue(task);//再次加入隊列里面,注意哦,id不變的
                }
                task.DoAction();
            }
            else 
            {
                task.DoAction();//執行委托

            }
        }
    }
	#endregion
	#region 私有方法
    private static AbstractTimeTask GetTimeTask(AbstractTimeTask task,uint start,int interval,Action action) 
    {
        task.Interval = interval;
        task.TimeId = ++TimeTaskManager.m_uiNextTimeId;
        task.NextTick = TimeTaskManager.m_uiTick + start;
        task.Action = action;
        return task;
    }
	#endregion
}

 注意:AddTimer的參數的單位是毫秒,不是秒。

接下來是實驗:

首先寫個Driver,作為驅動類。

using UnityEngine;
using System.Collections;
#region 模塊信息
/*----------------------------------------------------------------
// 模塊名:Driver
// 創建者:chen
// 修改者列表:
// 創建日期:2015.11.5
// 模塊描述:驅動類
//----------------------------------------------------------------*/
#endregion
public class Driver : MonoBehaviour
{
    void Start()
    {
        TimeTaskManager.AddTimer(5000, 5000, DebugTest);
        InvokeRepeating("Tick", 0, 0.02f);
    }
    void Update()
    {
        
    }
    void Tick()
    {
        TimeTaskManager.Tick();
    }
    void DebugTest()
    {
        Debug.Log("111");
    }
}

 創建一個空物體,然后賦予它這個腳本,作為驅動所有程序腳本。

運行,發現程序在5秒之后,每隔5秒打印一個111到控制台。

這個定時類,非常的有用,就比如說網絡通信啊,我們可以定時的發送心跳包,還有彈出警告窗口,計時多少秒之后自動關閉等等

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM