using System;
using System.Collections.Generic;
using System.Timers; public class PETimer {
private Action<string> taskLog; private static readonly string lockTid = "lockTid";
private DateTime startDateTime = new DateTime(, , , , , , );
private double nowTime; private int tid;
private List<int> tidLst = new List<int>();
private List<int> recTidLst = new List<int>(); private static readonly string lockTime = "lockTime";
private List<PETimeTask> tmpTimeLst = new List<PETimeTask>();
private List<PETimeTask> taskTimeLst = new List<PETimeTask>();
private List<int> tmpDelTimeLst = new List<int>(); private int frameCounter;
private static readonly string lockFrame = "lockFrame";
private List<PEFrameTask> tmpFrameLst = new List<PEFrameTask>();
private List<PEFrameTask> taskFrameLst = new List<PEFrameTask>();
private List<int> tmpDelFrameLst = new List<int>(); public PETimer(int interval = ) {
tidLst.Clear();
recTidLst.Clear(); tmpTimeLst.Clear();
taskTimeLst.Clear(); tmpFrameLst.Clear();
taskFrameLst.Clear();
} public void Update() {
CheckTimeTask();
CheckFrameTask(); DelTimeTask();
DelFrameTask(); if (recTidLst.Count > ) {
lock (lockTid) {
RecycleTid();
}
}
}
private void DelTimeTask() {
if (tmpDelTimeLst.Count > ) {
lock (lockTime) {
for (int i = ; i < tmpDelTimeLst.Count; i++) {
bool isDel = false;
int delTid = tmpDelTimeLst[i];
for (int j = ; j < taskTimeLst.Count; j++) {
PETimeTask task = taskTimeLst[j];
if (task.tid == delTid) {
isDel = true;
taskTimeLst.RemoveAt(j);
recTidLst.Add(delTid);
//LogInfo("Del taskTimeLst ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
break;
}
} if (isDel)
continue; for (int j = ; j < tmpTimeLst.Count; j++) {
PETimeTask task = tmpTimeLst[j];
if (task.tid == delTid) {
tmpTimeLst.RemoveAt(j);
recTidLst.Add(delTid);
//LogInfo("Del tmpTimeLst ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
break;
}
}
}
}
}
}
private void DelFrameTask() {
if (tmpDelFrameLst.Count > ) {
lock (lockFrame) {
for (int i = ; i < tmpDelFrameLst.Count; i++) {
bool isDel = false;
int delTid = tmpDelFrameLst[i];
for (int j = ; j < taskFrameLst.Count; j++) {
PEFrameTask task = taskFrameLst[j];
if (task.tid == delTid) {
isDel = true;
taskFrameLst.RemoveAt(j);
recTidLst.Add(delTid);
break;
}
} if (isDel)
continue; for (int j = ; j < tmpFrameLst.Count; j++) {
PEFrameTask task = tmpFrameLst[j];
if (task.tid == delTid) {
tmpFrameLst.RemoveAt(j);
recTidLst.Add(delTid);
break;
}
}
}
}
}
}
private void CheckTimeTask() {
if (tmpTimeLst.Count > ) {
lock (lockTime) {
//加入缓存区中的定时任务
for (int tmpIndex = ; tmpIndex < tmpTimeLst.Count; tmpIndex++) {
taskTimeLst.Add(tmpTimeLst[tmpIndex]);
}
tmpTimeLst.Clear();
}
} //遍历检测任务是否达到条件
nowTime = GetUTCMilliseconds();
for (int index = ; index < taskTimeLst.Count; index++) {
PETimeTask task = taskTimeLst[index];
if (nowTime.CompareTo(task.destTime) < ) {
continue;
}
else {
Action cb = task.callback;
try {
if (cb != null) {
cb();
} }
catch (Exception e) {
LogInfo(e.ToString());
} //移除已经完成的任务
if (task.count == ) {
taskTimeLst.RemoveAt(index);
index--;
recTidLst.Add(task.tid);
}
else {
if (task.count != ) {
task.count -= ;
}
task.destTime += task.delay;
}
}
}
}
private void CheckFrameTask() {
if (tmpFrameLst.Count > ) {
lock (lockFrame) {
//加入缓存区中的定时任务
for (int tmpIndex = ; tmpIndex < tmpFrameLst.Count; tmpIndex++) {
taskFrameLst.Add(tmpFrameLst[tmpIndex]);
}
tmpFrameLst.Clear();
}
} frameCounter += ;
//遍历检测任务是否达到条件
for (int index = ; index < taskFrameLst.Count; index++) {
PEFrameTask task = taskFrameLst[index];
if (frameCounter < task.destFrame) {
continue;
}
else {
Action cb = task.callback;
try {
if (cb != null) {
cb();
}
}
catch (Exception e) {
LogInfo(e.ToString());
} //移除已经完成的任务
if (task.count == ) {
taskFrameLst.RemoveAt(index);
index--;
recTidLst.Add(task.tid);
}
else {
if (task.count != ) {
task.count -= ;
}
task.destFrame += task.delay;
}
}
}
} #region TimeTask
public int AddTimeTask(Action callback, double delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = ) {
if (timeUnit != PETimeUnit.Millisecond) {
switch (timeUnit) {
case PETimeUnit.Second:
delay = delay * ;
break;
case PETimeUnit.Minute:
delay = delay * * ;
break;
case PETimeUnit.Hour:
delay = delay * * * ;
break;
case PETimeUnit.Day:
delay = delay * * * * ;
break;
default:
LogInfo("Add Task TimeUnit Type Error...");
break;
}
}
int tid = GetTid(); ;
nowTime = GetUTCMilliseconds();
lock (lockTime) {
tmpTimeLst.Add(new PETimeTask(tid, callback, nowTime + delay, delay, count));
}
return tid;
}
public void DeleteTimeTask(int tid) {
lock (lockTime) {
tmpDelTimeLst.Add(tid);
//LogInfo("TmpDel ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
} }
public bool ReplaceTimeTask(int tid, Action callback, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = ) {
if (timeUnit != PETimeUnit.Millisecond) {
switch (timeUnit) {
case PETimeUnit.Second:
delay = delay * ;
break;
case PETimeUnit.Minute:
delay = delay * * ;
break;
case PETimeUnit.Hour:
delay = delay * * * ;
break;
case PETimeUnit.Day:
delay = delay * * * * ;
break;
default:
LogInfo("Replace Task TimeUnit Type Error...");
break;
}
}
nowTime = GetUTCMilliseconds();
PETimeTask newTask = new PETimeTask(tid, callback, nowTime + delay, delay, count); bool isRep = false;
for (int i = ; i < taskTimeLst.Count; i++) {
if (taskTimeLst[i].tid == tid) {
taskTimeLst[i] = newTask;
isRep = true;
break;
}
} if (!isRep) {
for (int i = ; i < tmpTimeLst.Count; i++) {
if (tmpTimeLst[i].tid == tid) {
tmpTimeLst[i] = newTask;
isRep = true;
break;
}
}
} return isRep;
}
#endregion #region FrameTask
public int AddFrameTask(Action callback, int delay, int count = ) {
int tid = GetTid();
lock (lockTime) {
tmpFrameLst.Add(new PEFrameTask(tid, callback, frameCounter + delay, delay, count));
}
return tid;
}
public void DeleteFrameTask(int tid) {
lock (lockFrame) {
tmpDelFrameLst.Add(tid);
}
}
public bool ReplaceFrameTask(int tid, Action callback, int delay, int count = ) {
PEFrameTask newTask = new PEFrameTask(tid, callback, frameCounter + delay, delay, count); bool isRep = false;
for (int i = ; i < taskFrameLst.Count; i++) {
if (taskFrameLst[i].tid == tid) {
taskFrameLst[i] = newTask;
isRep = true;
break;
}
} if (!isRep) {
for (int i = ; i < tmpFrameLst.Count; i++) {
if (tmpFrameLst[i].tid == tid) {
tmpFrameLst[i] = newTask;
isRep = true;
break;
}
}
} return isRep;
}
#endregion
public void SetLog(Action<string> handle)
{
taskLog = handle;
} public void Reset() {
tid = ;
tidLst.Clear();
recTidLst.Clear(); tmpTimeLst.Clear();
taskTimeLst.Clear(); tmpFrameLst.Clear();
taskFrameLst.Clear(); taskLog = null;
} #region Tool Methonds
private int GetTid() {
lock (lockTid) {
tid += ; //安全代码,以防万一
while (true) {
if (tid == int.MaxValue) {
tid = ;
} bool used = false;
for (int i = ; i < tidLst.Count; i++) {
if (tid == tidLst[i]) {
used = true;
break;
}
}
if (!used) {
tidLst.Add(tid);
break;
}
else {
tid += ;
}
}
} return tid;
}
private void RecycleTid() {
for (int i = ; i < recTidLst.Count; i++) {
int tid = recTidLst[i]; for (int j = ; j < tidLst.Count; j++) {
if (tidLst[j] == tid) {
tidLst.RemoveAt(j);
break;
}
}
}
recTidLst.Clear();
}
private void LogInfo(string info) {
if (taskLog != null) {
taskLog(info);
}
}
private double GetUTCMilliseconds() {
TimeSpan ts = DateTime.UtcNow - startDateTime;
return ts.TotalMilliseconds;
}
#endregion } class PETimeTask
{
public int tid;
public Action callback;
public double destTime;//单位:毫秒
public double delay;
public int count; public PETimeTask(int tid, Action callback, double destTime, double delay, int count)
{
this.tid = tid;
this.callback = callback;
this.destTime = destTime;
this.delay = delay;
this.count = count;
}
} class PEFrameTask
{
public int tid;
public Action callback;
public int destFrame;
public int delay;
public int count; public PEFrameTask(int tid, Action callback, int destFrame, int delay, int count)
{
this.tid = tid;
this.callback = callback;
this.destFrame = destFrame;
this.delay = delay;
this.count = count;
}
} public enum PETimeUnit {
Millisecond,
Second,
Minute,
Hour,
Day
}

使用方法:

 //实例化计时类
PETimer pt = new PETimer();
//时间定时任务
pt.AddTimeTask(TimerTask, , PETimeUnit.Millisecond, );
//帧数定时任务
pt.AddFrameTask(FrameTask, , ); int tempID = pt.AddTimeTask(() => {
Debug.Log("定时等待替换......");
}, , PETimeUnit.Second, ); //定时任务替换
pt.ReplaceTimeTask(tempID, () => {
Debug.Log("定时任务替换完成......");
}, , PETimeUnit.Second, ); //定时任务删除
pt.DeleteTimeTask(tempID); //定时检测与处理由MonoBehaviour中的Update()函数来驱动
void Update() {
pt.Update();
}

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

Unity自定义定时器,模拟协程,脱离MonoBehavior控制的更多相关文章

  1. 【Unity优化】如何实现Unity编辑器中的协程

    Unity编辑器中何时需要协程 当我们定制Unity编辑器的时候,往往需要启动额外的协程或者线程进行处理.比如当执行一些界面更新的时候,需要大量计算,如果用户在不断修正一个参数,比如从1变化到2,这种 ...

  2. Unity脚本编程之——协程(Coroutine)

    本文翻译自Unity官方文档:https://docs.unity3d.com/Manual/Coroutines.html 专有名词: Coroutine 协程 Alpha 不透明度 当你调用一个函 ...

  3. Unity中巧用协程和游戏对象的生命周期处理游戏重启的问题

    主要用到协程(Coroutines)和游戏对象的生命周期(GameObject Lifecycle)基础知识,巧妙解决了游戏重启的问题. 关于协程,这里有篇文章我觉得写的非常好,理解起来也很容易.推荐 ...

  4. 【Unity优化】怎样实现Unity编辑器中的协程

    Unity编辑器中何时须要协程 当我们定制Unity编辑器的时候,往往须要启动额外的协程或者线程进行处理.比方当运行一些界面更新的时候,须要大量计算,假设用户在不断修正一个參数,比方从1变化到2.这种 ...

  5. Unity之"诡异"的协程

    为什么说是诡异的协程呢?首先从一个案例说起吧,示例如下: 游戏目标:让小车进入到对应颜色屋子里,即可获得一分.(转弯的道路可控)   为了让小车能够平滑转弯,小车的前进方向需要和车子的位置与圆心组成的 ...

  6. 【Unity笔记】使用协程(Coroutine)异步加载场景

    using UnityEngine; using System.Collections; using UnityEngine.SceneManagement; using System; public ...

  7. Unity带参数的协程

    两种方法都可以传递参数,代码如下: using UnityEngine; using System.Collections; public class Test : MonoBehaviour { v ...

  8. Unity协程(Coroutine)原理深入剖析再续

    Unity协程(Coroutine)原理深入剖析再续 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 前面已经介绍过对协程(Coroutine ...

  9. 聊一聊Unity协程背后的实现原理

    Unity开发不可避免的要用到协程(Coroutine),协程同步代码做异步任务的特性使程序员摆脱了曾经异步操作加回调的编码方式,使代码逻辑更加连贯易读.然而在惊讶于协程的好用与神奇的同时,因为不清楚 ...

随机推荐

  1. java8新特性学习笔记链接

    https://blog.csdn.net/yitian_66/article/details/81010434

  2. 自顶向下深入分析Netty(五)--Future

    再次回顾这幅图,在上一章中,我们分析了Reactor的完整实现.由于Java NIO事件驱动的模型,要求Netty的事件处理采用异步的方式,异步处理则需要表示异步操作的结果.Future正是用来表示异 ...

  3. Percona-Toolkit 之 pt-online-schema-change 总结

    pt-online-schema-change - ALTER tables without locking them. pt-online-schema-change alters a table' ...

  4. Sql题面试题

    哪位大神会此题,请给出答案,十分感谢! 哪位大神会此题,请给出答案,十分感谢!

  5. XML CDATA识别“<,>”

    http://www.w3school.com.cn/xml/xml_cdata.asp 术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Dat ...

  6. 爬虫---爬虫er与反爬虫er之间的斗争 转发

    转自:昵称:python修行路 https://www.cnblogs.com/zhaof/p/7326260.html

  7. json文件常用代码

    1.json数据内容格式化处理 package com.sklm.lhb.json; public class JsonFormatTool { /** * 单位缩进字符串. */ private s ...

  8. windows下redis 配置文件参数说明

    1.先看redis.windows.conf 文件 # Redis configuration file example # Note on units: when memory size is ne ...

  9. Catch That Cow (BFS广搜)

    问题描述: Farmer John has been informed of the location of a fugitive cow and wants to catch her immedia ...

  10. HVP plan

    HVP,hier verification plan,建立整个验证的plan,在验证后期,通过vcs的coverage db可以直接进行反标, 包括反标code coverage,function c ...