Update逻辑

IEnumerator/ IEnumerable

public interface IEnumerable
{  IEnumerator GetEnumerator();
}  public interface IEnumerator
{  bool MoveNext();  void Reset();  Object Current { get; }
}  

在两者的使用上,有下面几点需要注意

1、一个Collection要支持foreach方式的遍历,必须实现IEnumerable接口(亦即,必须以某种方式返回IEnumerator object)。
2、IEnumerator object具体实现了iterator(通过MoveNext(),Reset(),Current)。
3、从这两个接口的用词选择上,也可以看出其不同:IEnumerable是一个声明式的接口,声明实现该接口的class是“可枚举(enumerable)”的,但并没有说明如何实现枚举器(iterator);IEnumerator是一个实现式的接口,IEnumerator object就是一个iterator。
4、IEnumerable和IEnumerator通过IEnumerable的GetEnumerator()方法建立了连接,client可以通过IEnumerable的GetEnumerator()得到IEnumerator object,在这个意义上,将GetEnumerator()看作IEnumerator object的factory method也未尝不可。

yield return

使用yield语句可以暂停(pause)协同程序的执行,yield的返回值指定在什么时候继续(resume)协同程序。

yield return null; //暂停协同程序,下一帧再继续往下执行
yield new WaitForFixedUpdate (); //暂停协同程序,等到下一次调用FixedUpdate方法时再继续往下执行
yield return new WaitForSeconds(2);//暂停协同程序,2秒之后再继续往下执行
yield return StartCoroutine("SomeCortoutineMethod");//暂停此协同程序,开启SomeCortoutineMethod协同程序,直到SomeCortoutineMethod里的内容全部搞定。

StartCoroutine

在Unity3D中,使用MonoBehaviour.StartCoroutine方法即可开启一个协同程序,也就是说该方法必须在MonoBehaviour或继承于MonoBehaviour的类中调用。

在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启一个线程。区别在于使用字符串作为参数可以开启线程并在线程结束前终止线程,相反使用IEnumerator 作为参数只能等待线程的结束而不能随时终止(除非使用StopAllCoroutines()方法);另外使用字符串作为参数时,开启线程时最多只能传递 一个参数,并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制。

在Unity3D中,使用StopCoroutine(string methodName)来终止一个协同程序,使用StopAllCoroutines()来终止所有可以终止的协同程序,但这两个方法都只能终止该 MonoBehaviour中的协同程序。

还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程 序并不会再开启;如是将协同程序所在脚本的enabled设置为false则不会生效。这是因为协同程序被开启后作为一个线程在运行,而 MonoBehaviour也是一个线程,他们成为互不干扰的模块,除非代码中用调用,他们共同作用于同一个对象,只有当对象不可见才能同时终止这两个线 程。然而,为了管理我们额外开启的线程,Unity3D将协同程序的调用放在了MonoBehaviour中,这样我们在编程时就可以方便的调用指定脚本 中的协同程序,而不是无法去管理,特别是对于只根据方法名来判断线程的方式在多人开发中很容易出错,这样的设计保证了对象、脚本的条理化管理,并防止了重 名。

示例1

public class GameManager : MonoBehaviour {void Start() { Debug.Log("Starting " + Time.time);StartCoroutine(WaitAndPrint(2));Debug.Log("Done " + Time.time);}IEnumerator WaitAndPrint(float waitTime) { yield return new WaitForSeconds(waitTime); Debug.Log("WaitAndPrint " + Time.time);}
}

运行结果:

public class GameManager : MonoBehaviour {IEnumerator Start() {Debug.Log("Starting " + Time.time);yield return StartCoroutine(WaitAndPrint(2.0F));Debug.Log("Done " + Time.time);}IEnumerator WaitAndPrint(float waitTime) { yield return new WaitForSeconds(waitTime);Debug.Log("WaitAndPrint " + Time.time);}
}

运行结果:

再看一个yield return StartCoroutine嵌套的例子
 void Start () {Debug.Log("start1");StartCoroutine(Test());Debug.Log("start2");}IEnumerator Test(){Debug.Log("test1");yield return StartCoroutine(DoSomething());Debug.Log("test2");}IEnumerator DoSomething(){Debug.Log("load 1");yield return null;Debug.Log("load 2");}
执行结果:

start1

test1

load1

start2

load2

test2

这种StartCoroutine中嵌套一个yield return StartCoroutine,第一个StartCoroutine会等到第二个StartCoroutine中所有代码结束后再继续执行,而第二个StartCoroutine中的yield语句会先返回第一个,然后立即返回他的调用处,也就是调用处会继续执行,而第一个StartCoroutine会等待第二个执行完再继续执行。

示例二

场景如下,一个球一个平面。

球的控制器

using UnityEngine;
using System.Collections;public class SphereController : MonoBehaviour {private Vector3 target;public float smoothing = 7f;public Vector3 Target{get { return target; }set{target = value;StopCoroutine("Movement");StartCoroutine("Movement", target);Debug.Log("Move!");}}IEnumerator Movement(Vector3 target){while(Vector3.Distance(transform.position, target) > 0.05f){transform.position = Vector3.Lerp(transform.position, target, smoothing * Time.deltaTime);yield return null;}}}

下面的脚本拖拽到地面上

using UnityEngine;
using System.Collections;public class ClickSetPosition : MonoBehaviour {public SphereController sphereController;// Update is called once per framevoid Update(){if (Input.GetMouseButtonDown(0)){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;Physics.Raycast(ray, out hit);if (hit.collider.gameObject == gameObject){Debug.Log("Clicked!");Vector3 newTarget = hit.point + new Vector3(0, 0.5f, 0);sphereController.Target = newTarget;}}}
}

运行结果

参考

Unity协程(Coroutine)原理深入剖析再续 - http://dsqiu.iteye.com/blog/2049743

协同的理解 - http://www.cnblogs.com/shawnzxx/archive/2013/01/01/2841451.html

yield(C# 参考) - https://msdn.microsoft.com/zh-cn/library/9k7k7cf0.aspx

COROUTINES Unity Tutorial - http://unity3d.com/learn/tutorials/modules/intermediate/scripting/coroutines

Unity StartCoroutine 和 yield return 深入研究 -  http://www.cnblogs.com/fly-100/p/3910515.html

Coroutines document - https://docs.unity3d.com/Manual/Coroutines.html

IEnumerator/ IEnumerable/ yield return/ StartCoroutine 详解相关推荐

  1. break, continue, goto, return语句详解

    关于break,continue,goto,return语句区别详解(所有语言通用的语法知识) 一.break 1. break语句形式: break; 2. break语句功能: A. switch ...

  2. yield的用法详解

    版权声明:本文为CSDN博主「冯爽朗」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/mieleizhi0 ...

  3. python中yield的用法详解——最简单,最清晰的解释(转载)

    首先,如果你还没有对yield有个初步分认识,那么你先把yield看做"return",这个是直观的,它首先是个return,普通的return是什么意思,就是在程序中返回某个值, ...

  4. python中 yield 的用法详解——最简单,最清晰的解释(排序节省内存消耗)

    首先我要吐槽一下,看程序的过程中遇见了yield这个关键字,然后百度的时候,发现没有一个能简单的让我懂的,讲起来真TM的都是头头是道,什么参数,什么传递的,还口口声声说自己的教程是最简单的,最浅显易懂 ...

  5. python中yield的使用_python中yield的用法详解-转载

    原文链接:https://blog.csdn.net/mieleizhi0522/article/details/82142856 ,今天在写python爬虫的时候,循环的时候用到了yield,于是搜 ...

  6. Python中yield的用法详解——最简单,最清晰的解释

    yield关键字的使用 当函数中遇到yield关键字,类似于return代码会直接返回 当函数中使用yield关键字返回,那么在多此next中,从第二次开始,代码会从上一次结束的位置开始运行 首先,如 ...

  7. python协程系列(三)——yield from原理详解

    声明:本文将详细讲解python协程的实现机理,为了彻底的弄明白它到底是怎么一回事,鉴于篇幅较长,将彻底从最简单的yield说起从最简单的生成器开始说起,因为很多看到这样一句话的时候很懵,即" ...

  8. return view详解

    1.return View(); 返回值 类型:System.Web.Mvc.ViewResult将视图呈现给响应的 View() 结果. 注释 View() 类的此方法重载将返回一个具有空 View ...

  9. mvc viewresult html,return view 详解 MVC

    显示: 继承保护 我们上边所看到的Action都是return View();我们可以看作这个返回值用于解析一个aspx文件.而它的返回类型是ActionResult如 public ActionRe ...

最新文章

  1. 途家网获3亿美元融资,PMCAFF放送100元途家优惠券(途家内部员工专用)
  2. 精通 RPM 之校验篇_检验篇_检测篇
  3. c# datetime._C#| DateTime.GetHashCode()方法与示例
  4. 京东物流首架全货机首航 久未露面的刘强东还发声推广
  5. nginx php 104,记一次nginx 502排错经历:recv() failed (104: Connection reset by peer)
  6. mysql的binlog意义_带你解析MySQL binlog
  7. newgrp - 登录到新的用户组中
  8. classpath是什么
  9. C++:怎样把一个int转成4个字节?
  10. 河南省学业水平测试计算机题目,2015级河南学业水平考试试题及答案
  11. css 样式面板,CSS样式面板.ppt
  12. EXE文件反编译工具下载
  13. 首行缩进字符计算机怎么弄,首行缩进2字符如何设置
  14. java中protected_Java中protected方法访问权限的问题
  15. C语言编程练习题_02兰州烧饼
  16. [来自iPc.me] 技术文,绝对是牛叉的技术文!把妹高手谈如何跟刚搭讪
  17. 农业银行查询开户支行的方法
  18. JPA+Hibernate中常用的注解
  19. Mysql中删除语句delete、truncate、drop的区别
  20. 新浪顶级架构师保驾护航!国内首本大型分布式架构笔记浴火新生

热门文章

  1. linux下如何更改系统时间,Linux怎样修改系统时间date
  2. Why?VR全景,会让你的企业更有范!实体店机会来了
  3. 线性表对于什么时候选用顺序表?什么时候选用链表作为线性表的存储结构为宜?
  4. 解决:Unity打包后,无法在模拟器上运行
  5. 土壤水模型MARMITES
  6. java 品尝饮料_喝到味觉失灵,得出了这份网红饮料测评报告
  7. 高中计算机特长生,十所高中公布体育特长生招生方案
  8. XenServer假死状态
  9. 解决pip更新太慢或更新失败的问题
  10. reactive_Spring Reactive已经过时了吗? 螺纹连接反转