在本文,你将学到如何使用迭代器做一个通用的定时器。
写在前面:
写一个通用的定时器,就是说定时结束后对调用的对象的某些状态或值进行改变;
假如传入一个bool量,定时到了返回他的取反值,此处立马想到out 或者ref 来获得方法回值,但是可惜迭代器不能有ref或out参数:
解决思路:
不一定需要传入bool,直接委托也很OK,下面简单的代码演示一下这个不错的编程思路:
- 这个类定义了定时器:
using System;
using System.Collections;
using UnityEngine;
public class cycle {
public static IEnumerator DelayT(float _time, Action _cmd)
{
yield return new WaitForSeconds(_time);
_cmd.Invoke();
}
public static IEnumerator DelayTime(float _time, Action _cmd)
{
yield return new WaitForSeconds(_time);
_cmd.Invoke();
//下面死循环,测试手动退出协程
while (true)
{
Debug.Log(111);
yield return null;
}
}
}
- 这个类演示调用定时器
using UnityEngine;
public class cycleget : MonoBehaviour
{
private bool ifshow = false;
[Range(0,10)]
public float DelayTime = 1f;
void Start()
{
Debug.Log(gameObject.name+"初始状态字为false");
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
StartCoroutine(cycle.DelayT(Mathf.Clamp(DelayTime,0,10),
() => {
ifshow = !ifshow;
Debug.Log(gameObject.name+"时间到,状态改变"+ifshow.ToString());
}));
Debug.Log(gameObject.name + "按下鼠标左键,状态字为:" + ifshow.ToString());
}
//一般来说,协程运行完毕自动退出,哪有没有手动退出(或者人工干预停止协程)的方式?--答案是:有
//下面演示主动退出协程
if (Input.GetMouseButtonDown(1))
{
Coroutine coroutine = null;//1.先声明一个“Coroutine”的引用。
coroutine=StartCoroutine(cycle.DelayTime(Mathf.Clamp(DelayTime,0,10), //2.这个引用指向我们开启的那个协程
() => {
ifshow = !ifshow;
Debug.Log(gameObject.name+"时间到,状态改变"+ifshow.ToString());
StopCoroutine(coroutine);//3.在我们需要完成的事情后结束这个引用。此时死循环打印“111”就得到了有效遏制,也就是人工干预停止了协程
}));
Debug.Log(gameObject.name + "按下鼠标左键,状态字为:" + ifshow.ToString());
}
}
}
动画演示:
Tips: 没有加锁,协程连续点击连续执行,这点需要注意;
解决重复点击的问题可以用到数据结构,初步解决,思路可见下面的文章:
Unity3D 协程管理 - 简书
但不建议封装协程做定时器,笔者使用中发现会有安全问题哈。
Unity3D、IEnumerator 、通用定时器、Lambda、Action委托