• Unity自定义定时器,模拟协程,脱离MonoBehavior控制


      1 using System;
      2 using System.Collections.Generic;
      3 using System.Timers;
      4 
      5 public class PETimer {
      6     private Action<string> taskLog;
      7 
      8     private static readonly string lockTid = "lockTid";
      9     private DateTime startDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
     10     private double nowTime;
     11 
     12     private int tid;
     13     private List<int> tidLst = new List<int>();
     14     private List<int> recTidLst = new List<int>();
     15 
     16     private static readonly string lockTime = "lockTime";
     17     private List<PETimeTask> tmpTimeLst = new List<PETimeTask>();
     18     private List<PETimeTask> taskTimeLst = new List<PETimeTask>();
     19     private List<int> tmpDelTimeLst = new List<int>();
     20 
     21     private int frameCounter;
     22     private static readonly string lockFrame = "lockFrame";
     23     private List<PEFrameTask> tmpFrameLst = new List<PEFrameTask>();
     24     private List<PEFrameTask> taskFrameLst = new List<PEFrameTask>();
     25     private List<int> tmpDelFrameLst = new List<int>();
     26 
     27     public PETimer(int interval = 0) {
     28         tidLst.Clear();
     29         recTidLst.Clear();
     30 
     31         tmpTimeLst.Clear();
     32         taskTimeLst.Clear();
     33 
     34         tmpFrameLst.Clear();
     35         taskFrameLst.Clear();
     36     }
     37     
     38     public void Update() {
     39         CheckTimeTask();
     40         CheckFrameTask();
     41 
     42         DelTimeTask();
     43         DelFrameTask();
     44 
     45         if (recTidLst.Count > 0) {
     46             lock (lockTid) {
     47                 RecycleTid();
     48             }
     49         }
     50     }
     51     private void DelTimeTask() {
     52         if (tmpDelTimeLst.Count > 0) {
     53             lock (lockTime) {
     54                 for (int i = 0; i < tmpDelTimeLst.Count; i++) {
     55                     bool isDel = false;
     56                     int delTid = tmpDelTimeLst[i];
     57                     for (int j = 0; j < taskTimeLst.Count; j++) {
     58                         PETimeTask task = taskTimeLst[j];
     59                         if (task.tid == delTid) {
     60                             isDel = true;
     61                             taskTimeLst.RemoveAt(j);
     62                             recTidLst.Add(delTid);
     63                             //LogInfo("Del taskTimeLst ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
     64                             break;
     65                         }
     66                     }
     67 
     68                     if (isDel)
     69                         continue;
     70 
     71                     for (int j = 0; j < tmpTimeLst.Count; j++) {
     72                         PETimeTask task = tmpTimeLst[j];
     73                         if (task.tid == delTid) {
     74                             tmpTimeLst.RemoveAt(j);
     75                             recTidLst.Add(delTid);
     76                             //LogInfo("Del tmpTimeLst ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
     77                             break;
     78                         }
     79                     }
     80                 }
     81             }
     82         }
     83     }
     84     private void DelFrameTask() {
     85         if (tmpDelFrameLst.Count > 0) {
     86             lock (lockFrame) {
     87                 for (int i = 0; i < tmpDelFrameLst.Count; i++) {
     88                     bool isDel = false;
     89                     int delTid = tmpDelFrameLst[i];
     90                     for (int j = 0; j < taskFrameLst.Count; j++) {
     91                         PEFrameTask task = taskFrameLst[j];
     92                         if (task.tid == delTid) {
     93                             isDel = true;
     94                             taskFrameLst.RemoveAt(j);
     95                             recTidLst.Add(delTid);
     96                             break;
     97                         }
     98                     }
     99 
    100                     if (isDel)
    101                         continue;
    102 
    103                     for (int j = 0; j < tmpFrameLst.Count; j++) {
    104                         PEFrameTask task = tmpFrameLst[j];
    105                         if (task.tid == delTid) {
    106                             tmpFrameLst.RemoveAt(j);
    107                             recTidLst.Add(delTid);
    108                             break;
    109                         }
    110                     }
    111                 }
    112             }
    113         }
    114     }
    115     private void CheckTimeTask() {
    116         if (tmpTimeLst.Count > 0) {
    117             lock (lockTime) {
    118                 //加入缓存区中的定时任务
    119                 for (int tmpIndex = 0; tmpIndex < tmpTimeLst.Count; tmpIndex++) {
    120                     taskTimeLst.Add(tmpTimeLst[tmpIndex]);
    121                 }
    122                 tmpTimeLst.Clear();
    123             }
    124         }
    125 
    126         //遍历检测任务是否达到条件
    127         nowTime = GetUTCMilliseconds();
    128         for (int index = 0; index < taskTimeLst.Count; index++) {
    129             PETimeTask task = taskTimeLst[index];
    130             if (nowTime.CompareTo(task.destTime) < 0) {
    131                 continue;
    132             }
    133             else {
    134                 Action cb = task.callback;
    135                 try {
    136                     if (cb != null) {
    137                         cb();
    138                     }
    139                     
    140                 }
    141                 catch (Exception e) {
    142                     LogInfo(e.ToString());
    143                 }
    144 
    145                 //移除已经完成的任务
    146                 if (task.count == 1) {
    147                     taskTimeLst.RemoveAt(index);
    148                     index--;
    149                     recTidLst.Add(task.tid);
    150                 }
    151                 else {
    152                     if (task.count != 0) {
    153                         task.count -= 1;
    154                     }
    155                     task.destTime += task.delay;
    156                 }
    157             }
    158         }
    159     }
    160     private void CheckFrameTask() {
    161         if (tmpFrameLst.Count > 0) {
    162             lock (lockFrame) {
    163                 //加入缓存区中的定时任务
    164                 for (int tmpIndex = 0; tmpIndex < tmpFrameLst.Count; tmpIndex++) {
    165                     taskFrameLst.Add(tmpFrameLst[tmpIndex]);
    166                 }
    167                 tmpFrameLst.Clear();
    168             }
    169         }
    170 
    171         frameCounter += 1;
    172         //遍历检测任务是否达到条件
    173         for (int index = 0; index < taskFrameLst.Count; index++) {
    174             PEFrameTask task = taskFrameLst[index];
    175             if (frameCounter < task.destFrame) {
    176                 continue;
    177             }
    178             else {
    179                 Action cb = task.callback;
    180                 try {
    181                     if (cb != null) {
    182                         cb();
    183                     }
    184                 }
    185                 catch (Exception e) {
    186                     LogInfo(e.ToString());
    187                 }
    188 
    189                 //移除已经完成的任务
    190                 if (task.count == 1) {
    191                     taskFrameLst.RemoveAt(index);
    192                     index--;
    193                     recTidLst.Add(task.tid);
    194                 }
    195                 else {
    196                     if (task.count != 0) {
    197                         task.count -= 1;
    198                     }
    199                     task.destFrame += task.delay;
    200                 }
    201             }
    202         }
    203     }
    204 
    205     #region TimeTask
    206     public int AddTimeTask(Action callback, double delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1) {
    207         if (timeUnit != PETimeUnit.Millisecond) {
    208             switch (timeUnit) {
    209                 case PETimeUnit.Second:
    210                     delay = delay * 1000;
    211                     break;
    212                 case PETimeUnit.Minute:
    213                     delay = delay * 1000 * 60;
    214                     break;
    215                 case PETimeUnit.Hour:
    216                     delay = delay * 1000 * 60 * 60;
    217                     break;
    218                 case PETimeUnit.Day:
    219                     delay = delay * 1000 * 60 * 60 * 24;
    220                     break;
    221                 default:
    222                     LogInfo("Add Task TimeUnit Type Error...");
    223                     break;
    224             }
    225         }
    226         int tid = GetTid(); ;
    227         nowTime = GetUTCMilliseconds();
    228         lock (lockTime) {
    229             tmpTimeLst.Add(new PETimeTask(tid, callback, nowTime + delay, delay, count));
    230         }
    231         return tid;
    232     }
    233     public void DeleteTimeTask(int tid) {
    234         lock (lockTime) {
    235             tmpDelTimeLst.Add(tid);
    236             //LogInfo("TmpDel ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
    237         }
    238         
    239     }
    240     public bool ReplaceTimeTask(int tid, Action callback, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1) {
    241         if (timeUnit != PETimeUnit.Millisecond) {
    242             switch (timeUnit) {
    243                 case PETimeUnit.Second:
    244                     delay = delay * 1000;
    245                     break;
    246                 case PETimeUnit.Minute:
    247                     delay = delay * 1000 * 60;
    248                     break;
    249                 case PETimeUnit.Hour:
    250                     delay = delay * 1000 * 60 * 60;
    251                     break;
    252                 case PETimeUnit.Day:
    253                     delay = delay * 1000 * 60 * 60 * 24;
    254                     break;
    255                 default:
    256                     LogInfo("Replace Task TimeUnit Type Error...");
    257                     break;
    258             }
    259         }
    260         nowTime = GetUTCMilliseconds();
    261         PETimeTask newTask = new PETimeTask(tid, callback, nowTime + delay, delay, count);
    262 
    263         bool isRep = false;
    264         for (int i = 0; i < taskTimeLst.Count; i++) {
    265             if (taskTimeLst[i].tid == tid) {
    266                 taskTimeLst[i] = newTask;
    267                 isRep = true;
    268                 break;
    269             }
    270         }
    271 
    272         if (!isRep) {
    273             for (int i = 0; i < tmpTimeLst.Count; i++) {
    274                 if (tmpTimeLst[i].tid == tid) {
    275                     tmpTimeLst[i] = newTask;
    276                     isRep = true;
    277                     break;
    278                 }
    279             }
    280         }
    281 
    282         return isRep;
    283     }
    284     #endregion
    285 
    286     #region FrameTask
    287     public int AddFrameTask(Action callback, int delay, int count = 1) {
    288         int tid = GetTid();
    289         lock (lockTime) {
    290             tmpFrameLst.Add(new PEFrameTask(tid, callback, frameCounter + delay, delay, count));
    291         }
    292         return tid;
    293     }
    294     public void DeleteFrameTask(int tid) {
    295         lock (lockFrame) {
    296             tmpDelFrameLst.Add(tid);
    297         }
    298     }
    299     public bool ReplaceFrameTask(int tid, Action callback, int delay, int count = 1) {
    300         PEFrameTask newTask = new PEFrameTask(tid, callback, frameCounter + delay, delay, count);
    301 
    302         bool isRep = false;
    303         for (int i = 0; i < taskFrameLst.Count; i++) {
    304             if (taskFrameLst[i].tid == tid) {
    305                 taskFrameLst[i] = newTask;
    306                 isRep = true;
    307                 break;
    308             }
    309         }
    310 
    311         if (!isRep) {
    312             for (int i = 0; i < tmpFrameLst.Count; i++) {
    313                 if (tmpFrameLst[i].tid == tid) {
    314                     tmpFrameLst[i] = newTask;
    315                     isRep = true;
    316                     break;
    317                 }
    318             }
    319         }
    320 
    321         return isRep;
    322     }
    323     #endregion
    324     public void SetLog(Action<string> handle)
    325     {
    326         taskLog = handle;
    327     }
    328 
    329     public void Reset() {
    330         tid = 0;
    331         tidLst.Clear();
    332         recTidLst.Clear();
    333 
    334         tmpTimeLst.Clear();
    335         taskTimeLst.Clear();
    336 
    337         tmpFrameLst.Clear();
    338         taskFrameLst.Clear();
    339 
    340         taskLog = null;
    341     }
    342 
    343     #region Tool Methonds
    344     private int GetTid() {
    345         lock (lockTid) {
    346             tid += 1;
    347 
    348             //安全代码,以防万一
    349             while (true) {
    350                 if (tid == int.MaxValue) {
    351                     tid = 0;
    352                 }
    353 
    354                 bool used = false;
    355                 for (int i = 0; i < tidLst.Count; i++) {
    356                     if (tid == tidLst[i]) {
    357                         used = true;
    358                         break;
    359                     }
    360                 }
    361                 if (!used) {
    362                     tidLst.Add(tid);
    363                     break;
    364                 }
    365                 else {
    366                     tid += 1;
    367                 }
    368             }
    369         }
    370 
    371         return tid;
    372     }
    373     private void RecycleTid() {
    374         for (int i = 0; i < recTidLst.Count; i++) {
    375             int tid = recTidLst[i];
    376 
    377             for (int j = 0; j < tidLst.Count; j++) {
    378                 if (tidLst[j] == tid) {
    379                     tidLst.RemoveAt(j);
    380                     break;
    381                 }
    382             }
    383         }
    384         recTidLst.Clear();
    385     }
    386     private void LogInfo(string info) {
    387         if (taskLog != null) {
    388             taskLog(info);
    389         }
    390     }
    391     private double GetUTCMilliseconds() {
    392         TimeSpan ts = DateTime.UtcNow - startDateTime;
    393         return ts.TotalMilliseconds;
    394     }
    395     #endregion
    396 
    397     
    398 }
    399 
    400 class PETimeTask
    401 {
    402     public int tid;
    403     public Action callback;
    404     public double destTime;//单位:毫秒
    405     public double delay;
    406     public int count;
    407 
    408     public PETimeTask(int tid, Action callback, double destTime, double delay, int count)
    409     {
    410         this.tid = tid;
    411         this.callback = callback;
    412         this.destTime = destTime;
    413         this.delay = delay;
    414         this.count = count;
    415     }
    416 }
    417 
    418 class PEFrameTask
    419 {
    420     public int tid;
    421     public Action callback;
    422     public int destFrame;
    423     public int delay;
    424     public int count;
    425 
    426     public PEFrameTask(int tid, Action callback, int destFrame, int delay, int count)
    427     {
    428         this.tid = tid;
    429         this.callback = callback;
    430         this.destFrame = destFrame;
    431         this.delay = delay;
    432         this.count = count;
    433     }
    434 }
    435 
    436 public enum PETimeUnit {
    437     Millisecond,
    438     Second,
    439     Minute,
    440     Hour,
    441     Day
    442 }

    使用方法:

     1 //实例化计时类
     2 PETimer pt = new PETimer();
     3 //时间定时任务
     4 pt.AddTimeTask(TimerTask, 500, PETimeUnit.Millisecond, 3);
     5 //帧数定时任务
     6 pt.AddFrameTask(FrameTask, 100, 3);
     7 
     8 int tempID = pt.AddTimeTask(() => {
     9     Debug.Log("定时等待替换......");
    10 }, 1, PETimeUnit.Second, 0);
    11 
    12 //定时任务替换
    13 pt.ReplaceTimeTask(tempID, () => {
    14     Debug.Log("定时任务替换完成......");
    15 }, 2, PETimeUnit.Second, 0);
    16 
    17 //定时任务删除
    18 pt.DeleteTimeTask(tempID);
    19 
    20 //定时检测与处理由MonoBehaviour中的Update()函数来驱动
    21 void Update() {
    22     pt.Update();
    23 }

    转自https://github.com/PlaneZhong/PETimer

  • 相关阅读:
    android:sharedUserId
    SystemProperties cannot be resolved错误
    Mybatis(二)|搭建mybatis环境之注解版-简单搭配
    Eclipse构建Maven的SpringMVC项目
    IDEA新手使用教程(详解)(经典)
    IntelliJ IDEA 教程
    用注解的方式实现Mybatis插入数据时返回自增的主键Id
    eclipse使用git提交项目
    eclipse中使用自带git的常用操作
    myeclipse10.7安装git插件
  • 原文地址:https://www.cnblogs.com/huangzongyi/p/10579734.html
Copyright © 2020-2023  润新知