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. Java博客目录

    JavaWeb 1.Tomcat使用 2.Servlet入门 3.JSP&EL&JSTL 4.Listener&Filter Java框架 Hibernate 1.简介及初使用 ...

  2. Google Colab Free GPU Tutorial【转载】

    转自:https://medium.com/deep-learning-turkey/google-colab-free-gpu-tutorial-e113627b9f5d 1.Google Cola ...

  3. 移除Excel工作表密码保护小工具含C#源代码

    有朋友发了个Excel.xlsx文件给我,让我帮忙看看里面是怎么做出来的.打开审阅后发现,每个Excel工作表都添加了密码保护: 看不到里面的隐藏列和公式等等,感觉很神秘.于是研究了一下Excel文件 ...

  4. wangEditor编辑器 Vue基本配置项

    wangEditor编辑器 Vue基本配置项 1.Vue安装方法 npm i wangeditor -S <template> <div id='wangeditor'> &l ...

  5. Go 初体验 - 并发与锁.2 - sync.WaitGroup

    sync包里的WaitGroup主要用于协程同步 计数主协程创建的子线程 WaitGoup.Add(i) 调用清除标记方法WaitGroup.Done() 使用WaitGroup.Wait()来阻塞, ...

  6. webstorm编辑器使用

    1.自动生成vue文件模板,如图

  7. Angular4 管道

  8. vue 定义全局函数,监听android返回键事件

    vue 定义全局函数,监听android返回键事件 方法一:main.js 注入(1)在main.js中写入函数Vue.prototype.changeData = function (){ aler ...

  9. 2018.6.10数据结构串讲_HugeGun

    链接: https://pan.baidu.com/s/1uQwLZAT8gjENDWLDm7-Oig 密码: mk8p @echo off : ) shuju test test_ fc test. ...

  10. centos6删除mysql安装

    1.查看已经安装了的mysql包: 2.卸载mysql: 3.查看剩下的mysql安装包: 4.逐个删除剩下的mysql安装包: 5.删除完后再次查看,以确保已删除干净: 6.删除自己安装的mysql ...