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