协程任务是可以做定时器的,但是有个最大的问题,那就是必须用在脚本中,但是我们游戏的逻辑大部分都在C#代码中,所有需要封装一个不依赖与脚本实现的定时器。
代码如下:
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
public class WaitTimeManager {
class TaskBehaviour : MonoBehaviour { }
private static TaskBehaviour m_Task;
static WaitTimeManager()
{
GameObject go = new GameObject("#WaitTimeManager#");
GameObject.DontDestroyOnLoad(go);
m_Task = go.AddComponent<TaskBehaviour>();
}
static IEnumerator Coroutine(float time, UnityAction callback)
{
yield return new WaitForSeconds(time);
if (callback != null)
{
callback();
}
}
//等待
static public Coroutine WaitTime(float time,UnityAction callback)
{
return m_Task.StartCoroutine(Coroutine(time, callback));
}
//取消等待
static public void CancelWait(ref Coroutine coroutine)
{
if (coroutine != null)
{
m_Task.StopCoroutine(coroutine);
coroutine = null;
}
}
}
无论是脚本还是类,在需要定时器的地方调用它即可,相关代码如下:
//开启定时器
Coroutine coroutine = WaitTimeManager.WaitTime(5f, delegate
{
Debug.Log("等待5s后回调");
});
//等待过程中取消它
WaitTimeManager.CancelWait(ref coroutine);
定时器满足了经过多少秒回调的需求,但是游戏可能还需要一种定时回调。如一共10秒结束,但是每1秒回调一下。
继承CustomYieldInstruction后,就可以处理自定义协程程序了。keepWaiting表示是否继续让协程等待。
代码如下:
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
public class Example : MonoBehaviour {
IEnumerator Start()
{
yield return new CustomWait(10f, 1f,
() =>
{
Debug.Log("每过一秒调用一次" + Time.time);
});
Debug.Log("十秒结束");
}
public class CustomWait : CustomYieldInstruction
{
private UnityAction m_IntervalCallback;
private float m_StartTime;
private float m_LastTime;
private float m_Interval;
private float m_Time;
public CustomWait(float time, float interval, UnityAction callback)
{
//记录开始时间
m_StartTime = Time.time;
//记录上一次间隔时间
m_LastTime = Time.time;
//记录间隔调用时间
m_Interval = interval;
//记录总时间
m_Time = time;
//间隔回调
m_IntervalCallback = callback;
}
public override bool keepWaiting
{
get
{
//此方法返回false表示协程结束
if (Time.time - m_StartTime > m_Time)
{
return false;
}
else if(Time.time-m_LastTime>=m_Interval)
{
m_LastTime = Time.time;
m_IntervalCallback();
}
return true;
}
}
}
}