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. “tar: Removing leading `/’ from member names”的错误

    “tar: Removing leading `/’ from member names”的错误 使用tar打bz2压缩的时候报的错误,解决方案:加入参数: P (大写的屁) # tar -jcPf ...

  2. nuget包管理nuget服务器发布包时出现请求报错 406 (Not Acceptable)

    在window服务器上部署nuget服务器时,发布包时出现请求报错 406 (Not Acceptable) 验证用户名.密码正确的情况下,还是出现上面错误.后面跟踪服务器日志,发现window\te ...

  3. Seq2Seq ---学习笔记

    应用场景:机器翻译 与language model 不同 MT model 的a<0> 是由encoder 生成的. language model 的 a<0> 是 初始化的. ...

  4. Django框架详细介绍---认证系统

    在web开发中通常设计网站的登录认证.注册等功能,Django恰好内置了功能完善的用户认证系统 1.auth模块 from django.contrib import auth 模块源码 import ...

  5. eclipse导出可供项目引用的jar

    有两种,一种是导出直接可以运行的jar,一种是导出来供其他项目引用的.在这里,说的是第二种,第一种在我博客上面也有一篇转载的.1选中项目,选择Export 2选择JAR file 然后Next 3 s ...

  6. class类 __repr__ 与__str__

    >>> class Student(object):... def __init__(self, name):... self.name = name... def __str__( ...

  7. shell的输入参数

    $#  参数格式 $0 $1 $2 ...第一个,第二个参数...

  8. shell脚本的一些常用操作

    字符串长度: ${#string}可获取string字符串的长度,如下: jenkins@soft1pc:~$ str="who are you"jenkins@soft1pc:~ ...

  9. 2018-2019-2 20165335『网络对抗技术』Exp5:MSF基础应用

    主动攻击的实践: ms17_010(成功) 浏览器攻击的实践:ms14_064(成功) 客户端攻击的实践:adobe reader PDF的攻击(成功) 运用辅助模块的实践:VNC弱口令破解/绕过(失 ...

  10. C++中的纯虚方法

    在学习数据结构中优先级队列时遇到纯虚方法的定义,一时没想起来,便查了一下. 1.纯虚方法解决什么样的问题,为什么要设计出纯虚方法? 考虑下面的需求,基类声明了一个方法,这个方法只针对具体的子类才有意义 ...