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. MATLAB程序控制语句

    Matlab中的程序控制语句包括条件控制(Conditional Control).循环(Loop Control).异常处理(Error Control)和程序返回(Program Terminat ...

  2. 2018-2019-2 《网络对抗技术》Exp0 Kali安装 Week1 20165321

    安装kali 在vm里面新建虚拟机,选择典型 选择安装程序光盘镜像文件,系统出现无法检测此光盘镜像中的操作系统 虚拟机命名选择安装位置 给虚拟机分配的磁盘大小 点击自定义硬件,更改虚拟机硬件 选择Gr ...

  3. Scala简介、安装、函数、面向对象

    Scala是一门以java虚拟机(JVM)为目标运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言. scala命令行窗口,我们称之为REPL,是指:Read->Evalua ...

  4. Vmworkstation启用错误

    无法打开内核设备"\\.\Global\vmx86":系统找不到指定的文件. 是否在安装 VMwareWorksation 后重新引到 ? 问题解决   无法连接 MKS:套接字连 ...

  5. Linux 7.x 防火墙&端口

    Linux 7.x 防火墙&端口 查看当前防火墙的状态: # firewall-cmd --state 也可以使用指令:systemctl status firewall.service 启动 ...

  6. 关于java实现自定义曲线拟合的研究

    项目需要拟合曲线,使用java实现.采用了apache-commons-math3实现自定义的曲线. 作为apache开源的搞数学计算的超强的库,一直不受市场重视.为啥呢?经过研究,使用java这个强 ...

  7. Android -- 带你从源码角度领悟Dagger2入门到放弃(三)

    1, 前面两篇文章我们知道了怎么使用常用的四种标签,现在我们结合我们自己的项目中去简单的使用 在我们搭建项目的时候,一般会创建自己的Application,在里面进行一些初始化如一些第三方的Green ...

  8. 《高性能Mysql》解读---Mysql的事务和多版本并发

    1.base:ACID属性,并发控制 2.MySql事务的隔离级别有哪些,含义是什么? 3.锁知多少,读锁,写锁,排他锁,共享锁,间隙锁,乐观锁,悲观锁. 4.Mysql的事务与锁有什么关联?MySq ...

  9. 线性二次型调节器LQR/LQC算法解析及求解器代码(matlab)

    参考链接:http://120.52.51.14/stanford.edu/class/ee363/lectures/dlqr.pdf 本文参考讲义中的第20页PPT,根据Hamilton-Jacob ...

  10. html5 css练习 定位布局

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...