作为源生的C#程序员,可能已经非常了解委托(delegate)、行动(Action)以及C#的事件了,不过作为一个半道转C#的程序员而言,这些东西可能还是有些陌生的,虽然委托并非是C#独创,亦非是首创,C++的函数指针就完全类似于委托的功能,但很多东西没有委托的话实现起来还是很伤脑筋的。

本文主要介绍委托与unity协程之间组合开发的便利,实质上也是对平常的学习和工作中学到的东西做个记录。

一、委托

定义委托:public delegate void MyDelegate(int
_num);

//定义一个委托MyDelegate,如同定义一个类一样,此时的委托没有经过实例化是无法使用的,而他的实例化必须接收一个返回值和参数都与他等同的函数,此处的委托MyDelegate只能接收返回值为void,参数为一个int的函数

实例化委托:MyDelegate _MyDelegate=new MyDelegate(TestMod);

//以TestMod函数实例化一个MyDelegate类型的委托_MyDelegate,此处TestMod函数的定义就应如下:

public void TestMod(int
_num);

//之后调用_MyDelegate(100)时就完全等同于调用TestMod(100)

二、协程

定义协程:public IEnumerator MyCoroutine(){
};

//定义一个协程MyCoroutine,不同于定义类或委托,此时的协程是可以直接使用的,Unity的每一个执行周期里都会包含属于协程的那一部分,只要是场景中属于激活状态的物体(active为true),如同update那般,Unity在渲染的每一帧都会去查找该物体上是否存在协程部分的代码,若存在则加入该物体协程的执行周期,协程部分的代码会如同update那样被Unity每帧执行,当然不同于update的是,大部分协程内部不存在延时的话,一次执行之后便会跳出了,而且既然是处于Unity规定的生命周期里的模块,协程如同update一样当他们所在的物体属于未激活的话(active为false),该物体上所有脚本中包含的协程代码都是不会被执行的。

使用协程:StartCoroutine(MyCoroutine());

//使用StartCoroutine函数将协程MyCoroutine加入此脚本所在物体的协程执行周期内,如果在渲染的下一帧此物体依旧是处于激活状态的话,那么协程MyCoroutine中的代码便会得到Unity执行。

三、委托+协程

其实网上关于这个的例子很多,我在这里只是做个比较系统的归纳。

还记得Unity的Invoke("test",2)吗(延时2秒后执行函数test)?不得不说这是个很大的坑,test函数不能赋予参数不说,还必须得是在当前类里面的方法,而对于延时执行等控制时间轴的操作,这在任何一个项目中肯定都是不可少的,索性有协程,我们完全可以替换掉Invoke的作用。

我们可以自己写一个延时控制器:

/// <summary>
/// 延时执行
/// </summary>
/// <param name="action">执行的委托</param>
/// <param name="delaySeconds">延时等待的秒数</param>
public IEnumerator DelayToInvokeDo(Action action, float delaySeconds)
{
yield return new WaitForSeconds(delaySeconds);
action();
}
/// <summary>
/// 使用例子
/// </summary>
StartCoroutine(DelayToInvokeDo(delegate() {
task.SetActive(true);
task.transform.position = Vector3.zero;
task.transform.rotation = Quaternion.Euler(Vector3.zero);
task.doSomethings();
},1.5f));

我们可以看到这里的例子是在1.5秒之后执行一个匿名委托,该委托的内容是将游戏物体task激活,并设置其位置与旋转属性,然后可以做更多的事情。

不过好像有些缺陷,task这个变量是哪里来的?Unity能否识别?事实上无论task是本类的全局静态变量还是普通单例变量,甚至只是一个与此部分协程代码处在同一域中的局部变量,加入到协程执行周期以后,短期内他是不会被释放的,也就不用担心Unity在后续执行到task的SetActive的时候会报空引用的错了。

只不过我们确实可以将之完善一下,或许我想更好的控制task。

/// <summary>
/// 延时执行
/// </summary>
/// <param name="action">执行的委托</param>
/// <param name="obj">委托的参数</param>
/// <param name="delaySeconds">延时等待的秒数</param>
public IEnumerator DelayToInvokeDo(Action<GameObject> action, GameObject obj,float delaySeconds)
{
yield return new WaitForSeconds(delaySeconds);
action(obj);
}
/// <summary>
/// 使用例子
/// </summary>
StartCoroutine(DelayToInvokeDo(delegate(GameObject task) {
task.SetActive(true);
task.transform.position = Vector3.zero;
task.transform.rotation = Quaternion.Euler(Vector3.zero);
task.doSomethings();
},GameObject.Find("task1"),1.5f));

1.5秒之后执行一个匿名委托,该委托的内容是将游戏物体task激活,并设置其位置与旋转属性,然后可以做更多的事情,这里的task是我们从场景中获取的name为task1的物体,将之作为参数传入了委托中。

后续你可能需要更多的参数,更多的种类,不过那只需要在此基础上扩展就可以了,最后将协程DelayToInvokeDo放在一个全局脚本内,定义一个该脚本的静态变量,那么就可以在项目的任何位置加入这个协程了。

C#神器 委托 + Unity神器 协程的更多相关文章

  1. [Unity菜鸟] 协程Coroutine

    1.协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态. unity中StartCoroutine()就是协程,协程实际上是在一个线程中, ...

  2. Unity使用协程技术制作倒计时器

    先上效果图 图片资源来自http://www.51miz.com/ 1.素材准备 在http://www.51miz.com/搜索png格式的数字图片,用Unity自带的图集制作工具,进行分割.Con ...

  3. 关于Unity中协程、多线程、线程锁、www网络类的使用

    协程 我们要下载一张图片,加载一个资源,这个时候一定不是一下子就加载好的,或者说我们不一定要等它下载好了才进行其他操作,如果那样的话我就就卡在了下载图片那个地方,傻住了.我们希望我们只要一启动加载的命 ...

  4. Unity在协程(Coroutines)内开启线程(Threading )

    孙广东  2017.6.13 http://blog.csdn.NET/u010019717 为什么要在协程中开启线程, 因为很多时候我们是需要线程执行完成后回到主线程的.然后主线程在继续执行后续的操 ...

  5. unity 之协程返回值

    yield return null; // 下一帧再执行后续代码yield return 6;//(任意数字) 下一帧再执行后续代码yield break; //直接结束该协程的后续操作yield r ...

  6. 关于Unity的协程

    协程 认识协程 //协程不是多线程:是一段在主程序之外执行的代码 //协程不受生命周影响 //作用:能够口直代码在特定的时间执行. //1,延时操作 //2,等待某代码执行结束之后执行 /* 特点:1 ...

  7. 【Unity】协程Coroutine及Yield常见用法

    最近学习协程Coroutine,参考了别人的文章和视频教程,感觉协程用法还是相当灵活巧妙的,在此简单总结,方便自己以后回顾.Yield关键字的语意可以理解为“暂停”. 首先是yield return的 ...

  8. Unity在协程内部停止协程自身后代码执行问题

    当在协程内部停止自身后,后面的代码块还会继续执行,直到遇到yield语句才会终止. 经测试:停止协程,意味着就是停止yield,所以在停止协程后,yield之后的语句也就不会执行了. 代码如下: us ...

  9. 发现一个小坑的地方,unity的协程,想要停止,必须以字符串启动

    今天想要停止一个协成,发现调用 StopCoroutine(ShowDebug()); 竟然不管用,后来看了文档才知道,原来想要停止协成,必须用字符启动协程 StartCoroutine(" ...

随机推荐

  1. 使用Fiddler改变线上js文件的引用路径

    一般的项目开发都是先在本地环境开发,测试环境中完成测试,最后再提交到线上环境. 但是由于版本构建工具有时出现bug或者一些缓存的因素导致测试环境代码可能和线上不一样,这是多么蓝瘦的事情.此处说的是在原 ...

  2. Linux下安装 mysql 5.7

    安装环境:系统是 centos6.5 1.下载 下载地址:https://dev.mysql.com/downloads/file/?id=467556 下载版本:我这里选择的57.17,通用版,li ...

  3. android 欢迎界面的制作

    再打开手机app的时候,最先映入我们眼帘的是一个覆盖手机全屏的欢迎界面,在这个界面显示出来的时候整个手机屏幕只会显示这一个界面,上面的标题栏,以及手机最顶端的状态栏都会消失,只有欢迎页面结束跳转到其他 ...

  4. linux 3.10 串口注册

    这个调用过程特别奇特,值得记下来. 最外层调用start_kernel的console_init()进行串口注册. console_init()调用drivers/tty/tty_io.c: void ...

  5. JQuery写的一个常见的banner

    大致的布局如下: <div class="banner" >                <div class="pic">      ...

  6. 关于基因组注释文件GTF的解释

    GTF文件的全称是gene transfer format,主要是对染色体上的基因进行标注.怎么理解呢,其实所谓的基因名,基因座等,都只是后来人们给一段DNA序列起的名字而已,还原到细胞中就是细胞核里 ...

  7. Docker镜像的实现原理

    Docker 镜像是怎么实现增量的修改和维护的? 每个镜像都由很多层次构成,Docker 使用 Union FS 将这些不同的层结合到一个镜像中去. 通常 Union FS 有两个用途, 一方面可以实 ...

  8. 安卓高级6 SnackBar

    引言 文/李牧羊(简书作者) 原文链接:http://www.jianshu.com/p/2654e6bda3b1 著作权归作者所有,转载请联系作者获得授权,并标注"简书作者". ...

  9. Java经典设计模式之七大结构型模式(附实例和详解)

    博主在大三的时候有上过设计模式这一门课,但是当时很多都基本没有听懂,重点是也没有细听,因为觉得没什么卵用,硬是要搞那么复杂干嘛.因此设计模式建议工作半年以上的猿友阅读起来才会理解的比较深刻.当然,你没 ...

  10. 永远不要在循环之外调用wait方法

    1. 前言 随着摩尔定律的失效,Amdahl定律成为了多核计算机性能发展的指导.对于现在的java程序员们来说,并发编程越来越重要和习以为常.很惭愧和恐慌的是我对java的并发编程一直是只知道概念,入 ...