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到控制台。

这个定时类,非常的有用,就比如说网络通信啊,我们可以定时的发送心跳包,还有弹出警告窗口,计时多少秒之后自动关闭等等

时间: 2024-10-14 12:45:21

Unity3d通用工具类之定时触发器的相关文章

Unity3d通用工具类之NGUI图集分解

---恢复内容开始--- Unity3d通用工具类之NGUI图集分解 由于最近需要一些美术资源吗,但是无奈自己不会制作UI,所以就打算去网上的项目中直接找几张可以使用的贴图资源. 但是发现这些资源已经被NGUI自带的打包图集工具打包好了,而且原小贴图也已经全部删掉了,只剩下一个预制物. 那么这个预制物里面包含什么呢: 1.一张大图集贴图 2.大贴图的材质球 3.挂上UIAtla脚本的预制物 那么重点来了,我们该如何获取这张大贴图中的小贴图呢? 这里我写了个小插件,我直接在NGUI源代码里面改:

Unity3d通用工具类之数据配置加载类

今天,我们来讲讲游戏中的数据配置加载. 什么是游戏数据加载呢?一般来说游戏中会有场景地图. 按照国际惯例,先贴一张游戏场景的地图: 在这张地图上,我们可以看到有很多正六边形,正六边形上有树木.岩石等. 哎!那么问题也就来了.大家会思考这张地图怎么啦.关游戏数据配置有什么关系?我们做好场景直接loding进来不就行了? 这也就是问题所在,如果你是直接loding进场景有很多问题: 1.场景是死的.只能是这个做好的场景.如果你想删除一些正六边形,想改变一些树木的位置,如何完成.有人会想,那我再做一个

Unity3d通用工具类之解压缩文件

今天,我们来写写c#是如何通过代码解压缩文件的. 在游戏的项目中呢,常常我们需要运用到解压缩的技术.比如,当游戏需要更新的时候,我们会从服务器中下载更新的压缩文件包. 这时候我们就需要解压文件,然后覆盖添加到游戏文件夹去,实现游戏的更新. 通常我们就需要通过代码来实现这一功能. 那么这里呢,我用的是第三发的压缩库,这个是用到一个dll,也就是ICSharpCode.SharpZipLib.Zip.dll 读者可以自行百度下载,这里我提供链接给你们: http://pan.baidu.com/s/

Unity3d通用工具类之生成文件的MD5

今天我们来写写工具类,这个类有什么用呢? 也就是无论你做什么项目,这个工具类你都可以拿来用,之所以通用,是可以适用所有项目. 这节我主要讲如何生成文件的MD5码. 那么这个MD5是个什么鬼东西,读者可以自行百度,其实简略的讲就是验证文件是否被篡改. 什么意思,比如当你去网站下载游戏的客户端软件,当有些黑客喜欢搞出点不好的事情,在你的客户端加些恶意代码之类的. 当黑客改了客户端文件,随之这个文件的MD5也改变了.所以我们只要验证用户下载的客户端的MD5和网站提供的MD5码是否一致,来判断是否要下载

Unity3D普通类和继承自MonoBehaviour类的区别

欢迎来到unity学习.unity培训.unity企业培训教育专区,这里有很多U3D资源.U3D培训视频.U3D教程.U3D常见问题.U3D项目源码,我们致力于打造业内unity3d培训.学习第一品牌. Unity3D普通类和继承自MonoBehaviour类的区别.如果创建新的类时,使用的是在unity editor的project视图中右键,create javascript or c#方式,那么创建的类都是默认继承自MonoBehaviour, 生成后可以查看类文件,会发现c#类继承自Mo

本地数据Store。Cookie,Session,Cache的理解。Timer类主要用于定时性、周期性任务 的触发。刷新Store,Panel

本地数据Store var monthStore = Ext.create('Ext.data.Store', { storeId : 'monthStore', autoLoad : false, fields : [ 'MONTH_' ], data : [ { MONTH_ : '1' }, { MONTH_ : '2' }, { MONTH_ : '3' }, { MONTH_ : '4' }, { MONTH_ : '5' }, { MONTH_ : '6' }, { MONTH_ :

Android RecyclerView单击、长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类

?? Android RecyclerView单击.长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类 我写的附录文章2,介绍了Android如何基于OnItemTouchListener +GestureDetector实现单击.长按事件的监听,由于如今RecyclerView在Android开发是如此的普遍,以及RecyclerView的单击事件是如此的常用,如果像附录文章2那样把一堆事件监听写到业务逻辑代码里面,那得写

java 导出xls 通用工具类

java  导出xls 通用工具类 package org.rui..util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.M

提取jedis源码的一致性hash代码作为通用工具类

一致性Hash热点 一致性Hash算法是来解决热点问题,如果虚拟节点设置过小热点问题仍旧存在. 关于一致性Hash算法的原理我就不说了,网上有很多人提供自己编写的一致性Hash算法的代码示例,我在跑网上的代码示例发现还是有热点问题.为此我翻阅了Jedis的ShardedJedis类的源码把它的一致性Hash算法提取出来,作为自己的一个工具类,以后自己工程开发中用起来也放心些,毕竟jedis的代码经受了大家的验证. 提取jedis的一致性hash代码作为通用工具类 看看人家码神写的代码,这泛型,这