Unity常用协程功能封装

# 1.前言
unity开发过程中,经常用到一些特定的协程功能,比如延时触发、等待触发、重复操作等。unity自带Invoke以及InvokeRepeating方法,但这些方法均采用反射机制,性能消耗,而且代码混淆时极其容易出错。所以再次对这些功能做以下简单封装。方便后续使用。
# 2.CoroutineJobCenter
CoroutineJobCenter封装了需要的基本方法。
## 2.1 延时触发
延时一定事件触发。
```csharp
public IEnumerator StartJobDelayed(float delayedTime, Action action)
{
yield return new WaitForSeconds(delayedTime);

if (action != null)
{
action();
}
}

public IEnumerator StartJobDelayed<T>(float delayedTime, Action<T> action, T t)
{
yield return new WaitForSeconds(delayedTime);

if (action != null)
{
action(t);
}
}
```
## 2.2 等待触发
等待某一条件返回true时触发,采用unity自带的WaitUntil类。

```csharp
public IEnumerator StartJobUntil(Func<bool> funtion, Action action)
{
yield return new WaitUntil(funtion);

if (action != null)
{
action();
}
}

public IEnumerator StartJobUntil<T>(Func<bool> funtion, Action<T> action, T t)
{
yield return new WaitUntil(funtion);

if (action != null)
{
action(t);
}
}
```
## 2.3 重复触发
### 2.3.1 每隔一帧触发,并规定触发次数。

```csharp
public IEnumerator RepeatJobPerFrame(int count, Action action)
{
for (int i = 0; i < count; i++)
{
yield return null;

if (action != null)
{
action();
}
}
}

public IEnumerator RepeatJobPerFrame<T>(int count, Action<T> action, T t)
{
for (int i = 0; i < count; i++)
{
yield return null;

if (action != null)
{
action(t);
}
}
}
```
### 2.3.2 每隔固定时间触发,并规定触发次数。

```csharp
public IEnumerator RepeatJobPerTimespan(int count, float interval, Action action)
{
yield return new RepeatJobPerTimespan(action, count, interval);
}
```

```csharp
public class RepeatJobPerTimespan : CustomYieldInstruction
{
private Action action;
private int count;
private int repeatCount;
private float timeSpan;
private float startedTime;

public override bool keepWaiting
{
get
{
if (repeatCount >= count)
{
return false;
}
else if(Time.time - startedTime >= timeSpan)
{
startedTime = Time.time;
repeatCount++;

if (action != null)
{
action();
}
}

return true;
}
}

public RepeatJobPerTimespan(Action action, int count, float timeSpan)
{
this.action = action;
this.count = count;
this.timeSpan = timeSpan;
startedTime = Time.time;
repeatCount = 0;
}
}
```
### 2.3.3 规定时间内,间隔触发
**注意:**
由于间隔多长时间 触发的时间间隔并不精确,所以会影响触发次数。比如每隔两秒执行一次,一共执行六秒。则不会执行三次,因为每次等待两秒,根据判断肯定会超过两秒。所以不会有第三次执行。此时可以适当放宽总时间或者减小时间间隔。
```csharp
public IEnumerator RepeatJobInCertainTimeSpan(float timeSpan, float interval, Action action)
{
yield return new RepeatJobInCertainTimespan(action, interval, timeSpan);
}
```

```csharp
public class RepeatJobInCertainTimespan : CustomYieldInstruction
{
private Action action;
private float startTime;
private float lastJobTime;
private float interval;
private float timeSpan;

public override bool keepWaiting
{
get
{
if (Time.time - startTime > timeSpan)
{
return false;
}
else if (Time.time - lastJobTime >= interval)
{
lastJobTime = Time.time;

if (action != null)
{
action();
}
}
return true;
}
}

public RepeatJobInCertainTimespan(Action action, float interval, float timeSpan)
{
this.action = action;
this.interval = interval;
this.timeSpan = timeSpan;
this.startTime = Time.time;
this.lastJobTime = Time.time;
}
}
```

## 2.4 规定的时间内等待触发
这是一个比较常用的方法,比如超时等待。即如果在规定的时间内完成或者超过规定的时间,则进行下一步处理。

```csharp
public IEnumerator WaitUntilInCertainTimespan(float timeSpan, Func<bool> function, Action action)
{
yield return new WaitUntilInCertaiTime(function, timeSpan);

if (action != null)
{
action();
}
}
```

```csharp
public class WaitUntilInCertaiTime : CustomYieldInstruction
{
private Func<bool> function;
private float timeSpan;
private float startTime;

public override bool keepWaiting
{
get
{
if (function() || Time.time - startTime > timeSpan)
{
return false;
}
return true;
}
}

public WaitUntilInCertaiTime(Func<bool> function,float timeSpan)
{
this.function = function;
this.timeSpan = timeSpan;
startTime = Time.time;
}
}
```
# 3.应用

```csharp
using CoroutineJob;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CorountineJobTest : MonoBehaviour
{
public Button button;

private bool flag = false;

private void Start()
{
button.onClick.AddListener(OnStateChange);

//StartCoroutine(CoroutineJobCenter.Instance.StartJobUntil(() => { return flag; }, () =>
//{
// Debug.Log("StartJobUntil");
//}));

//StartCoroutine(CoroutineJobCenter.Instance.RepeatJobPerTimespan(5, 2, () =>
//{
// Debug.Log("RepeatJobPerTimespan");
//}));

//StartCoroutine(CoroutineJobCenter.Instance.RepeatJobInCertainTimeSpan(6, 1.8f, () =>
//{
// Debug.Log("RepeatJobInCertainTimeSpan");
//}));

StartCoroutine(CoroutineJobCenter.Instance.WaitUntilInCertainTimespan(6, () => { return flag; }, () =>
{
Debug.Log("RepeatJobInCertainTimeSpan");
}));
}

void OnStateChange()
{
flag = true;
}

}

```

上一篇:python – 合并pandas数据帧,其中一个值介于两个其他值之间


下一篇:C#检查时间范围是否在时间范围和多少小时之间