private void Start() {
ThreadStart threadStart = new ThreadStart(ThreadMain);
Thread thread = new Thread(threadStart);
thread.Start();
Debug.Log("UnityMain线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
}
void ThreadMain() {
Debug.Log("New线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
//运行会报错:get_transform can only be called from the main thread.
Debug.Log(transform.gameObject.name);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameRoot : MonoBehaviour
{
private void Start()
{
//StartCoroutine(FuncA());//可以传很多参数
StartCoroutine("FuncA");//只能传一个参数,用逗号链接
}
IEnumerator FuncA()
{
Debug.Log("Log1:");
yield return new WaitForSeconds(2f);
Debug.Log("Log2:");
}
}
两种协程启动和关闭的方法需要匹配,不然可能出现关闭不了的情况
StartCoroutine("FuncA");//只能传一个参数,用逗号链接
StopCoroutine("FuncA");
Coroutine cot;
cot = StartCoroutine(FuncA());//可以传很多参数
StopCoroutine(cot);
1.协程,顾名思义,就是“协同程序”,用来实现协作。 2.比如在游戏中需要等待1秒后执行一个操作。我们不能让游戏主线程卡死等1秒,而是开启一个协程进行协作,协程同样是由主线程来驱动(所以说它不是线程),会在每一帧去检测它是否已经达到了完成的条件。比如条件是1秒后执行一个操作,那么在1秒后主线程对它检测时。条件满足,于是就执行先前设定好的相关操作。
yeild break;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//功能:计时系统
public class TimerSystem : MonoBehaviour
{
public static TimerSystem Instance;
private void Awake()
{
Instance = this;
}
public void AddTimerTask()
{
Debug.Log("Add Time Task");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//功能:启动入口
public class GameRoot : MonoBehaviour
{
private void Start()
{
TimerSystem.Instance.AddTimerTask();
}
}
修改GameRoot和TimerSystem脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//功能:启动入口
public class GameRoot : MonoBehaviour
{
private void Start()
{
Debug.Log("Game Start...");
TimerSystem timerSystem = GetComponent();
timerSystem.InitSys();
}
public void ClickAddBtn()
{
TimerSystem.Instance.AddTimerTask();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//功能:计时系统
//开发目标:
//支持时间定时,帧定时
//定时任务可循环,可取消,可替换
//使用简单,调用方便
public class TimerSystem : MonoBehaviour
{
public static TimerSystem Instance;
public void InitSys()
{
Instance = this;
Debug.Log("TimeSys Init Done.");
}
private void Update()
{
//遍历检测任务是否达到条件 TODO
}
public void AddTimerTask()
{
Debug.Log("Add Time Task");
}
}
创建一个PETimeTask类
//定时任务的数据类
using System;
class PETimeTask
{
public float destTime;
public Action callback;
}
修改TimerSystem里面的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//功能:计时系统
//开发目标:
//支持时间定时,帧定时
//定时任务可循环,可取消,可替换
//使用简单,调用方便
public class TimerSystem : MonoBehaviour
{
public static TimerSystem Instance;
private List taskTimeList = new List();
public void InitSys()
{
Instance = this;
Debug.Log("TimeSys Init Done.");
}
private void Update()
{
//遍历检测任务是否达到条件
for(int index = 0; index < taskTimeList.Count; index++)
{
PETimeTask task = taskTimeList[index];
if(Time.realtimeSinceStartup < task.destTime)
{
continue;
}
else
{
Action cb = task.callback;
if(cb != null)
{
cb();
}
//移除已经完成的任务
taskTimeList.RemoveAt(index);
index--;
}
}
}
public void AddTimerTask(Action callback, float delay)
{
float destTime = Time.realtimeSinceStartup + delay;
PETimeTask timeTask = new PETimeTask();
timeTask.destTime = destTime;
timeTask.callback = callback;
taskTimeList.Add(timeTask);
}
}
在GameRoot里面进行调用
public void ClickAddBtn()
{
Debug.Log("Add Time Task");
TimerSystem.Instance.AddTimerTask(FuncA,2.0f);
}
void FuncA()
{
Debug.Log("Delay Log");
}
新增一个tempTaskList用来进行缓存,现将所有的任务放进缓存,然后在从缓存放进taskTimeList。
private List tempTimeList = new List();//缓存列表
在Update里添加下面代码
//加入缓存区中的定时任务
for(int index = 0; index < tempTimeList.Count; index++)
{
taskTimeList.Add(tempTimeList[index]);
}
tempTimeList.Clear();
默认PETimeTask里面的destTime为毫秒。添加几个枚举类型来表示其他时间单位
public enum PETimeUnit
{
Millisecond,
Second,
Minute,
Hour,
Day
}
更新TimeSystem里面的方法,添加时间转变的的方法
//首先要换算单位
if (timeUnit != PETimeUnit.Millisecond)
{
switch (timeUnit)
{
case PETimeUnit.Second:
delay = delay * 1000;
break;
case PETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case PETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case PETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
Debug.Log("Add Task TimeUnit Type Error...");
break;
}
}
修改PETimeTask类和TimeSystem
//定时任务的数据类
using System;
class PETimeTask
{
public float destTime;//记录开始运行的时间 单位是毫秒
public float delay;//延迟的时间
public Action callback;
public int count;//执行次数 0:表示该方法一直执行
public PETimeTask(Action callback,float destTime,float delay,int count)
{
this.callback = callback;
this.destTime = destTime;
this.delay = delay;
this.count = count;
}
}
public enum PETimeUnit
{
Millisecond,
Second,
Minute,
Hour,
Day
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//功能:计时系统
//开发目标:
//支持时间定时,帧定时
//定时任务可循环,可取消,可替换
//使用简单,调用方便
public class TimerSystem : MonoBehaviour
{
public static TimerSystem Instance;
private List tempTimeList = new List();//缓存列表
private List taskTimeList = new List();
public void InitSys()
{
Instance = this;
Debug.Log("TimeSys Init Done.");
}
private void Update()
{
//加入缓存区中的定时任务
for(int index = 0; index < tempTimeList.Count; index++)
{
taskTimeList.Add(tempTimeList[index]);
}
tempTimeList.Clear();
//遍历检测任务是否达到条件
for(int index = 0; index < taskTimeList.Count; index++)
{
PETimeTask task = taskTimeList[index];
//当实际时间小于应该运行的时间,说明程序已经运行过,跳过
if(Time.realtimeSinceStartup * 1000 < task.destTime)
{
continue;
}
else
{
Action cb = task.callback;
if(cb != null)
{
cb();
}
//移除已经完成的任务
if(task.count == 1)
{
taskTimeList.RemoveAt(index);
index--;
}
else
{
if (task.count != 0)
task.count -= 1;
task.destTime += task.delay;
}
}
}
}
public void AddTimerTask(Action callback, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond,int count = 1)
{
//首先要换算单位
if (timeUnit != PETimeUnit.Millisecond)
{
switch (timeUnit)
{
case PETimeUnit.Second:
delay = delay * 1000;
break;
case PETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case PETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case PETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
Debug.Log("Add Task TimeUnit Type Error...");
break;
}
}
float destTime = Time.realtimeSinceStartup * 1000 + delay;
PETimeTask timeTask = new PETimeTask(callback, destTime,delay, count);
tempTimeList.Add(timeTask);
}
}
如何扩展取消定时任务?
1.生成全局唯一ID
2.通过ID索引操作任务
给PETimeTask添加id
public int tid;
修改TimeSystem中的部分代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//功能:计时系统
//开发目标:
//支持时间定时,帧定时
//定时任务可循环,可取消,可替换
//使用简单,调用方便
public class TimerSystem : MonoBehaviour
{
public static TimerSystem Instance;
private static readonly string obj = "lock";
private int tid;
private List tidList = new List();
private List tempTimeList = new List();//缓存列表
private List taskTimeList = new List();
public void InitSys()
{
Instance = this;
Debug.Log("TimeSys Init Done.");
}
private void Update()
{
//加入缓存区中的定时任务
for(int index = 0; index < tempTimeList.Count; index++)
{
taskTimeList.Add(tempTimeList[index]);
}
tempTimeList.Clear();
//遍历检测任务是否达到条件
for(int index = 0; index < taskTimeList.Count; index++)
{
PETimeTask task = taskTimeList[index];
//当实际时间小于应该运行的时间,说明程序已经运行过,跳过
if(Time.realtimeSinceStartup * 1000 < task.destTime)
{
continue;
}
else
{
Action cb = task.callback;
if(cb != null)
{
cb();
}
//移除已经完成的任务
if(task.count == 1)
{
taskTimeList.RemoveAt(index);
index--;
}
else
{
if (task.count != 0)
task.count -= 1;
task.destTime += task.delay;
}
}
}
}
public void AddTimerTask(Action callback, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond,int count = 1)
{
//首先要换算单位
if (timeUnit != PETimeUnit.Millisecond)
{
switch (timeUnit)
{
case PETimeUnit.Second:
delay = delay * 1000;
break;
case PETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case PETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case PETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
Debug.Log("Add Task TimeUnit Type Error...");
break;
}
}
int tid = GetTid();
float destTime = Time.realtimeSinceStartup * 1000 + delay;
PETimeTask timeTask = new PETimeTask(tid,callback, destTime,delay, count);
tempTimeList.Add(timeTask);
tidList.Add(tid);
}
private int GetTid()
{
lock (obj)
{
tid += 1;
//安全代码,以防万一
while (true)
{
if (tid == int.MaxValue)
{
tid = 0;
}
bool used = false;
for(int i = 0; i < tidList.Count; i++)
{
if(tid == tidList[i])
{
used = true;
break;
}
}
if (!used)
{
break;
}
else
{
tid += 1;
}
}
}
return tid;
}
}
修改GameRoot里面的方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//功能:启动入口
public class GameRoot : MonoBehaviour
{
private void Start()
{
Debug.Log("Game Start...");
TimerSystem timerSystem = GetComponent();
timerSystem.InitSys();
}
int tid;
public void ClickAddBtn()
{
Debug.Log("Add Time Task");
tid = TimerSystem.Instance.AddTimerTask(FuncA,1000,PETimeUnit.Millisecond,0);
}
void FuncA()
{
Debug.Log("tid:" + tid);
}
public void ClickDelBtn()
{
Debug.Log("Del Time Task");
bool ret = TimerSystem.Instance.DeleteTimeTask(tid);
Debug.Log("Del Time Task:" + ret);
}
}
在TimeSystem里面添加删除的方法
public bool DeleteTimeTask(int tid)
{
bool exist = false;
for(int i = 0; i < taskTimeList.Count; i++)
{
PETimeTask task = taskTimeList[i];
if(task.tid == tid)
{
taskTimeList.RemoveAt(i);
for(int j = 0; j < tidList.Count; j++)
{
if(tidList[j] == tid)
{
tidList.RemoveAt(j);
break;
}
}
}
exist = true;
break;
}
if (!exist)
{
for (int i = 0; i < tempTimeList.Count; i++)
{
PETimeTask task = tempTimeList[i];
if (task.tid == tid)
{
taskTimeList.RemoveAt(i);
for (int j = 0; j < tidList.Count; j++)
{
if (tidList[j] == tid)
{
tidList.RemoveAt(j);
break;
}
}
}
exist = true;
break;
}
}
return exist;
}
GameRoot里面添加下面的代码
public void ClickRepBtn()
{
Debug.Log("Rep Time Task");
bool ret = TimerSystem.Instance.ReplaceTimeTask(tid, FuncB, 2000);
Debug.Log("Rep Time Task:" + ret);
}
void FuncB()
{
Debug.Log("New Task Replace Done." );
}
TimeSystem中添加替换的功能
public bool ReplaceTimeTask(int tid, Action callback, float delay, PETimeUnit timeUnit = PETimeUnit.Millisecond, int count = 1)
{
//首先要换算单位
if (timeUnit != PETimeUnit.Millisecond)
{
switch (timeUnit)
{
case PETimeUnit.Second:
delay = delay * 1000;
break;
case PETimeUnit.Minute:
delay = delay * 1000 * 60;
break;
case PETimeUnit.Hour:
delay = delay * 1000 * 60 * 60;
break;
case PETimeUnit.Day:
delay = delay * 1000 * 60 * 60 * 24;
break;
default:
Debug.Log("Add Task TimeUnit Type Error...");
break;
}
}
float destTime = Time.realtimeSinceStartup * 1000 + delay;
PETimeTask newTask = new PETimeTask(tid, callback, destTime, delay, count);
bool isRep = false;
for (int i = 0; i < taskTimeList.Count; i++)
{
if(taskTimeList[i].tid == tid)
{
taskTimeList[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tempTimeList.Count; i++)
{
if (tempTimeList[i].tid == tid)
{
tempTimeList[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
对在tidList里重复的全局ID进行清除,在Update里面添加下面的代码
if (recTList.Count > 0)
RecycleTid();
private void RecycleTid()
{
for(int i = 0; i < recTList.Count; i++)
{
int tid = recTList[i];
for(int j = 0; j < tidList.Count; j++)
{
if(tidList[j]== tid)
{
tidList.Remove(j);
break;
}
}
}
recTList.Clear();
}
参考之前的TimeTask来开发FrameTask
首先是PETimeTask类中
//支持帧定时的类
class PEFrameTask
{
public int tid;
public int destFrame;//帧数
public int delay;
public Action callback;
public int count;//执行次数 0:表示该方法一直执行
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;
}
}
在TimerSystem中添加新的方法
private List tempFrameList = new List();//缓存列表
private List taskFrameList = new List();
private int frameCounter;
private void CheckFrameTask()
{
//加入缓存区中的定时任务
for (int index = 0; index < tempFrameList.Count; index++)
{
taskFrameList.Add(tempFrameList[index]);
}
tempFrameList.Clear();
frameCounter += 1;
//遍历检测任务是否达到条件
for (int index = 0; index < taskFrameList.Count; index++)
{
PEFrameTask task = taskFrameList[index];
//当实际时间小于应该运行的时间,说明程序已经运行过,跳过
if (frameCounter < task.destFrame)
{
continue;
}
else
{
Action cb = task.callback;
try
{
if (cb != null)
{
cb();
}
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
//移除已经完成的任务
if (task.count == 1)
{
taskFrameList.RemoveAt(index);
index--;
recTList.Add(task.tid);
}
else
{
if (task.count != 0)
task.count -= 1;
task.destFrame += task.delay;
}
}
}
}
#region FrameTask
public int AddFrameTask(Action callback, int delay, int count = 1)
{
int tid = GetTid();
PEFrameTask frameTask = new PEFrameTask(tid, callback, frameCounter+delay, delay, count);
tempFrameList.Add(frameTask);
tidList.Add(tid);
return tid;
}
public bool DeleteFrameTask(int tid)
{
bool exist = false;
for (int i = 0; i < taskFrameList.Count; i++)
{
PEFrameTask task = taskFrameList[i];
if (task.tid == tid)
{
taskFrameList.RemoveAt(i);
for (int j = 0; j < tidList.Count; j++)
{
if (tidList[j] == tid)
{
tidList.RemoveAt(j);
break;
}
}
}
exist = true;
break;
}
if (!exist)
{
for (int i = 0; i < tempFrameList.Count; i++)
{
PEFrameTask task = tempFrameList[i];
if (task.tid == tid)
{
taskFrameList.RemoveAt(i);
for (int j = 0; j < tidList.Count; j++)
{
if (tidList[j] == tid)
{
tidList.RemoveAt(j);
break;
}
}
}
exist = true;
break;
}
}
return exist;
}
public bool ReplaceFrameTask(int tid, Action callback, int delay, int count = 1)
{
PEFrameTask newTask = new PEFrameTask(tid, callback, frameCounter+delay, delay, count);
bool isRep = false;
for (int i = 0; i < taskFrameList.Count; i++)
{
if (taskFrameList[i].tid == tid)
{
taskFrameList[i] = newTask;
isRep = true;
break;
}
}
if (!isRep)
{
for (int i = 0; i < tempFrameList.Count; i++)
{
if (tempFrameList[i].tid == tid)
{
tempFrameList[i] = newTask;
isRep = true;
break;
}
}
}
return isRep;
}
#endregion
在GameRoot里面添加三个按钮进行检测
public void ClickAddFrameBtn()
{
//使用Lamda表达式添加任务
Debug.Log("Add Frame Task");
tid = TimerSystem.Instance.AddFrameTask(() =>
{
Debug.Log("Frame tid:" + tid + " " + System.DateTime.Now);
}, 50, 0);
}
public void ClickDelFrameBtn()
{
Debug.Log("Del Time Task");
bool ret = TimerSystem.Instance.DeleteFrameTask(tid);
Debug.Log("Del Frame Task:" + ret);
}
public void ClickRepFrameBtn()
{
Debug.Log("Rep Frame Task");
bool ret = TimerSystem.Instance.ReplaceFrameTask(tid, FuncB, 100);
Debug.Log("Rep Frame Task:" + ret);
}