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. Redis 开发规范

    本文主要介绍在使用阿里云Redis的开发规范,从下面几个方面进行说明. 键值设计 命令使用 客户端使用 相关工具 通过本文的介绍可以减少使用Redis过程带来的问题. 一.键值设计 1.key名设计 ...

  2. 学号20175313 《实现Linux下cp XXX1 XXX2的功能(一)》第九周

    目录 MyCP 一.题目要求 二.题目理解 三.需求分析 四.设计思路 五.伪代码分析 六.代码链接 七.代码实现过程中遇到的问题 八.运行结果截图 九.参考资料 MyCP 一.题目要求 编写MyCP ...

  3. AngularJS简单例子

    双大括号标记{{}}绑定的表达式 <html ng-app> <script src="http://code.angularjs.org/angular-1.0.1.mi ...

  4. python基础之 序列化,os,sys,random,hashlib

    1.序列化 定义: JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.简单地说,JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然 ...

  5. Oracle中exp导出与imp导入的参数(full,owner/formuser/touser)测试

    1.exp导出的参数(FULL,OWNER)测试 先知道的一点是full不能与owner共存,还有都是以用户的方式导出(在这里),其中不仅仅包括表,这可能就是下面报warnings的原因,因为Orac ...

  6. git 解决授权失败的方法

    git 提示  fatal: Authentication failed for 'http://***********‘’得解决方法 首先用 git config --list 查看一下 如果不对, ...

  7. Leetcode: The Maze III(Unsolved Lock Problem)

    There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolli ...

  8. 1231: ykc买零食

    1231: ykc买零食时间限制: 1 Sec  内存限制: 128 MB 题目描述 ykc的班级准备举行班级聚会,而身为生活委员的ykc要为此准备好零食,这天,ykc来到了学校的新起点超市,在转了3 ...

  9. 深入理解javascript原型和闭包(转)

    深入理解javascript原型和闭包(完结)   说明: 该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的 ...

  10. mongols的反向代理和负载均衡功能

    mongols是C++ 服务器基础设施库,它最近更新提供了反向代理和负载均衡功能. 以下为用mongols代理两个nodejs后端(8888和8889)并与nginx压测对比图: 压测显示mongol ...