协程应用——制作简单的计时器
来源:互联网 发布:石油大学华东 网络登录 编辑:程序博客网 时间:2024/06/14 16:15
前言
协程作为Unity中一个比较重要的特性,当前有很多种奇妙的特性。这次就简单介绍一下如何使用Coroutine写一个可以复用的计时器(Timer)。如果你对协程不是很熟悉,建议可以先阅读一下我之前写的一篇 协程(Coroutine)原理分析。
Timer的常规实现
大部分情况下, 我们可以通过直接在Update(或FixedUpdate)中使用Time.deltaTime来获取上一帧经过的时间,这样通过一个变量累加该值就可以实现计时器的效果。大致代码如下:
using UnityEngine;public class Timer : MonoBehaviour{ public float waitTime = 1f; private float elapseTime; void Update() { elapseTime += Time.deltaTime; if (elapseTime > waitTime) { print("Timer is done"); elapseTime = 0; } }}
这种写法基本不会有什么问题,不过我觉得还是有两个缺点的。第一个是每次你使用的使用的时候都需要在Update中加入这段话,我只在Update()中做这一项操作的话还好,如果之后功能越添越多就会显得有点乱。第二个来说就是没有那么准确,基本每次timer的值都会大于waitTimer,帧数高的话这种误差倒还说得过去,帧数低就会有比较可观的累积误差。
Timer的协程实现方法
接下来就介绍一下如何用协程实现计时器的功能。这里就需要用到Unity内置的YieldInstruction之一————WaitForSeconds,即悬停Coroutine指定的秒数然后继续执行。此外由于我们可以通过使用StartCoroutine和StopCoroutine手动地启动和停止协程,Timer的功能也会更加完善。
下面是可供参考的Timer的协程实现代码:
using UnityEngine;//使用协程必须添加该命名空间,//因为IEnumerator就位于该命名空间下using System.Collections;public class Timer : MonoBehaviour{ public float waitTime = 1f; private float elapseTime; private void Start() { StartCoroutine(CustomeTimer()); } IEnumerator CustomeTimer() { yield return new WaitForSeconds(waitTime); print("Timer is done."); //使用StartCoroutine()实现CustomerTimer()的迭代执行 StartCoroutine(CustomeTimer()); }}
Timer的协程复用
如你所见,使用协程可以在任何我们愿意的地方启动Timer, 并且可以随时通过调用StopCoroutine来暂停它们。然而这样做还是有一个弊端,那就是无法复用。当我们希望在另一个项目中使用的时候还是得把这些代码再写一遍,作为一个懒癌晚期的程序猿,这种情况简直不可原谅。所以我们需要再在现有代码的基础上把它改成一个可复用的库文件。
如果希望达到这个目的,有一个地方是必须被舍弃的,即StartCoroutine/StopCoroutine的使用。如果你仔细研究Unity Script API,那么你会发现 StartCoroutine/StopCoroutine属于MonoBehaviour的public functions。 简单地解释就是只有在MonoBehaviour对象里使用这两个函数才会有用。你可能会问我们使用MonoBehaviour啊,为什么可以用。那是因为所有C#脚本的默认模板都是继承自MonoBehaviour的,所以使用的时候StartCoroutine()其实等价于this.StartCoroutine()。那么这对我们编写可复用的脚本有哪些影响呢?最大的问题就是如果我们在库文件中使用这两个文件,那么就必须把库文件挂到某个游戏物体上才会生效,这显然很蠢。理想的做法还是我们在库文件里写好协程相关的代码(因为协程是C#的特性, 所以即使不继承自MonoBehaviour也可以使用), 然后在需要使用Timer的脚本中使用StartCoroutine/StopCoroutine引用。
下面给出可供参考的代码:
namespace liusuwanxia.Timer{ using System; using System.Collections; using UnityEngine; /// <summary> /// Ready to use timers for coroutines /// </summary> /// <summary> /// Ready to use timers for coroutines /// </summary> public class Timer { /// <summary> /// 简单的正计时器, 可以指定每次停顿时执行的动作 /// </summary> /// <param name="duration">停顿的间隔</param> /// <param name="callback">停顿时调用的函数</param> /// <returns></returns> public static IEnumerator Start(float duration, Action callback) { return Start(duration, false, callback); } /// <summary> /// 简单的正计时器, 可以指定每次停顿时执行的动作 /// </summary> /// <param name="duration">每次停顿的间隔</param> /// <param name="repeat">是否重复执行</param> /// <param name="callback">停顿时调用的函数</param> /// <returns></returns> public static IEnumerator Start(float duration, bool repeat, Action callback) { do { yield return new WaitForSeconds(duration); if (callback != null) callback(); } while (repeat); } public static IEnumerator StartRealtime(float time, System.Action callback) { float start = Time.realtimeSinceStartup; while (Time.realtimeSinceStartup < start + time) { yield return null; } if (callback != null) callback(); } public static IEnumerator NextFrame(Action callback) { yield return new WaitForEndOfFrame(); if (callback != null) callback(); } }}
下面是使用的示例:
using liusuwanxia.Timer;using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;public class test : MonoBehaviour { public Text textTimer; private IEnumerator coroutine; private int count = 60; // Use this for initialization void Start () { coroutine = Timer.Start(1f, true, () => { if (count <= 0) StopCoroutine(coroutine); textTimer.text = string.Format("Timer: {0}", count--); }); } public void OnBtnStartClick() { StartCoroutine(coroutine); } public void OnBtnStopClick() { StopCoroutine(coroutine); }}
总结
使用协程制作的计时器具有自由开启停止,精准高效等优点,不过相对于一般方法确实更难理解。个人建议在基本掌握Coroutine的用法之后,再试着理解和使用上述工具类。
- 协程应用——制作简单的计时器
- 简单计时器的制作
- 计时器的简单应用
- 简单的协程计时器
- 第八章、图像处理与动画制作——图像控件和计时器的应用
- 用javascript制作的简单毫秒计时器
- JavaScript制作简单计时器
- 计时器的制作
- 计时器的制作
- 安卓实战项目之制作简单的计时器
- iOS——NSTimer的使用,计时器的简单创建
- boost的timer计时器类源码——简单、干脆
- 一个简单的计时器
- JS简单的计时器
- JS简单的计时器
- 简单的计时器
- 一个简单的计时器
- 简单的计时器
- vim中":x"和":wq"的区别
- traceroute 检测
- [HAOI2011][BZOJ2302] problem C 组合数+动态规划
- SQL Join的一些总结
- 第九章:vue2中路由的使用
- 协程应用——制作简单的计时器
- Java中LinkedList的一些方法—addFirst addFirst getFirst geLast removeFirst removeLast
- 数据结构实验之排序一:一趟快排
- Xshell远程连接CentOS-7版的Linux
- 论述HTTP协议的描述!
- JZOJ1444. 交换【推荐】(2017.8B组)
- liunx中udp服务器与客户端创建
- CSS2常用属性
- 51nod 1192 Gcd表中的质数 莫比乌斯反演