Unity3D协同程序(Coroutine)

摘要下:

1.html

coroutine, 中文翻译“协程”。这个概念可能有点冷门,不过百度之,说是一种很古老的编程模型了,之前的操做系统里进程调度里用到过,如今操做系统的进程调度都是根据 时间片和优先级来进行轮换,之前是要程序本身来释放cpu的控制权,一直不释放一直也就占用着cpu,这种要求程序本身来进行调度的编程模型应该就叫“协 程”了。程序员

协程和线程差很少,线程的调度是由操做系统完成的,协程把这项任务交给了程序员本身实现,固然也就能够提升灵活性,另外协程的开销比线程要小,在程序里能够开更多的协程。编程

一些语言里自带了对coroutine的实现,好比lua。c里面虽然没有coroutine,不过windows下提供了一种叫fiber的机制,叫作“纤程”,算是一种轻量级线程。windows

 

2.函数

一。什么是协同程序post

       协同程序,即在主程序运行时同时开启另外一段逻辑处理,来协同当前程序的执行。换句话说,开启协同程序就是开启一个线程性能

 

二。协同程序的开启与终止ui

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

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

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

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

个人一些粗浅小结:

1.Coroutines顾名思议是用来协助主要进程的,在Unity中感受就是一个可动态添加和移除的Update()函数。它的调用在全部Update函数以后。

Unity原文:

  • If you start a coroutine in LateUpdate it will also be called after LateUpdate just before rendering.
  • Coroutines are executed after all Update functions.

2.yield就像是一个红绿灯,在知足紧跟在它后面的条件以前,这个协程会挂起,把执行权交给调用它的父函数,知足条件时就能够执行yield下面的代码。

Unity原文:

Normal coroutine updates are run after the Update function returns. A coroutine is function that can suspend its execution (yield) until the given given YieldInstruction finishes. Different uses of Coroutines:

  • yield;等待 all Update functions 已被call过,The coroutine will continue on the next frame.
  • yield WaitForSeconds(2);Continue after a specified time delay, after all Update functions have been called for the frame
  • yield WaitForFixedUpdate();Continue after all FixedUpdate has been called on all scripts
  • yield WWWContinue after a WWW download has completed.
  • yield StartCoroutine(MyFunc); Chains the coroutine, and will wait for the MyFunc coroutine to complete first.

 

协同的用法

Yield中断:(有中断就表明程序停在该处,等待yield后的时间结束再继续执行后面的语句。)

http://unity3d.com/support/documentation/ScriptReference/index.Coroutines_26_Yield.html

http://game.ceeger.com/Script/Overview/Overview.Coroutines_Yield.html

注意:

  • 在unity C#中yield(中断)语句必需要在IEnumerator类型里

  • C#方法,方法的返回类型为IEnumerator,返回值如(eg: yield return new WaitForSeconds(2); 或者 yield return null;)。

  • yields不能够在Update或者FixedUpdate里使用。


示例:
这个例子将执行Do,可是do以后的print会马上执行:

复制代码
using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
public static IEnumerator Do() {
  print("Do now");
  yield return new WaitForSeconds(2);
  print("Do 2 seconds later");
}
void Awake() {
  Do();    //执行DO,可是do后的语句继续执行
  print("This is printed immediately");
}
复制代码

这个例子将执行Do,并等待,直到Do完成再执行其余语句:

复制代码
using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    IEnumerator Do() {
        print("Do now");
        yield return new WaitForSeconds(2);
        print("Do 2 seconds later");
    }
    IEnumerator Awake() {
        yield return StartCoroutine("Do");    //Yield StartCoroutine就表明中断式的协同工做
        print("Also after 2 seconds");
        print("This is after the Do coroutine has finished execution");
    }
}
复制代码

Coroutine协同:(为何要有Coroutine的概念? 由于有中断的存在,试想一个程序都靠Yield来暂停的话,如何作到一个事件暂停的过程当中,暂停过程当中继续执行后面的程序? 那么就要靠Coroutine来实现。)

http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.StartCoroutine.html?from=YieldInstruction 

http://game.ceeger.com/Script/MonoBehaviour/MonoBehaviour.StartCoroutine.html

  • 能够在UPdate或者FixedUpdate里使用coroutine
  • 这里有两种:StartCoroutine(协同工做) 和 yield return StartCoroutine(中断式的协同工做)
  • 有yield的表明先执行完本语句(无论多长时间),或者执行完本yield方法调用,才执行后续语句。例如StartCoroutine(WaitAndPrint(2.0F)),继续执行StartCoroutine后面的语句,
  • 没有yield的表明继续顺序执行。例如:yield return StartCoroutine(WaitAndPrint(2.0F)),表明StartCoroutine(WaitAndPrint(2.0F))函数里等待所有执行完,再执行StartCoroutine后面的语句

 StartCoroutine的例子:

复制代码
// In this example we show how to invoke a coroutine and continue executing
// the function in parallel.
// 此例演示如何调用协同程序和它的执行
function Start() {
    // - After 0 seconds, prints "Starting 0.0"
    // - After 0 seconds, prints "Before WaitAndPrint Finishes 0.0"
    // - After 2 seconds, prints "WaitAndPrint 2.0"
    // 先打印"Starting 0.0"和"Before WaitAndPrint Finishes 0.0"两句,2秒后打印"WaitAndPrint 2.0"
    print ("Starting " + Time.time );
    // Start function WaitAndPrint as a coroutine. And continue execution while it is running
    // this is the same as WaintAndPrint(2.0) as the compiler does it for you automatically
    // 协同程序WaitAndPrint在Start函数内执行,能够视同于它与Start函数同步执行.
    StartCoroutine(WaitAndPrint(2.0)); 
    print ("Before WaitAndPrint Finishes " + Time.time );
}

function WaitAndPrint (waitTime : float) {
    // suspend execution for waitTime seconds
    // 暂停执行waitTime秒
    yield WaitForSeconds (waitTime);
    print ("WaitAndPrint "+ Time.time );
}
复制代码

C# 版本

复制代码
using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Start() {
    print("Starting " + Time.time);
        StartCoroutine(WaitAndPrint(2.0F));
        print("Before WaitAndPrint Finishes " + Time.time);
    }
    IEnumerator WaitAndPrint(float waitTime) {
        yield return new WaitForSeconds(waitTime);
        print("WaitAndPrint " + Time.time);
    }
}
复制代码

yield return StartCoroutine的例子:

复制代码
// In this example we show how to invoke a coroutine and wait until it 
// is completed
// 在这个例子中咱们演示如何调用协同程序并直到它执行完成.
function Start() {
    // - After 0 seconds, prints "Starting 0.0"
    // - After 2 seconds, prints "WaitAndPrint 2.0"
    // - After 2 seconds, prints "Done 2.0"
    // 0秒时打印"Starting 0.0",2秒后打印"WaitAndPrint 2.0"和"Done 2.0"
    print ("Starting " + Time.time );
    // Start function WaitAndPrint as a coroutine. And wait until it is completed.
    // the same as yield WaitAndPrint(2.0);
    // 运行WaitAndPrint直到完成
    yield StartCoroutine(WaitAndPrint(2.0));
    print ("Done " + Time.time );
}

function WaitAndPrint (waitTime : float) {
    // suspend execution for waitTime seconds
    // 等待waitTime秒
    yield WaitForSeconds (waitTime);
    print ("WaitAndPrint "+ Time.time );
}
复制代码

C#版本

复制代码
using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    IEnumerator Start() {
        print("Starting " + Time.time);
        yield return StartCoroutine(WaitAndPrint(2.0F));
        print("Done " + Time.time);
    }
    IEnumerator WaitAndPrint(float waitTime) {
        yield return new WaitForSeconds(waitTime);
        print("WaitAndPrint " + Time.time);
    }
}
复制代码

 C#中的Coroutine与JavaScript中的区别:

1:Coroutines 必需要是 IEnumerator 返回类型:

IEnumerator MyCoroutine()
{
    //This is a coroutine
}

2:在C#中要使用 yield return而不是yield :

Remember that we need to return an IEnumerable, so the Javascript yield; becomes yield return 0; in C#

IEnumerator MyCoroutine()
{
    DoSomething();
    yield return 0; //Wait one frame, the 0 here is only because we need to return an IEnumerable
    DoSomethingElse();
}

since C# requires you to use the new operator to create objects, if you want to use WaitForSeconds you have to use it like this:

IEnumerator MyCoroutine()
{
    DoSomething();
    yield return new WaitForSeconds(2.0f);  //Wait 2 seconds
    DoSomethingElse();
}

3:调用Coroutine要使用 StartCoroutine 方法:

复制代码
public class MyScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(MyCoroutine());
    }
 
    IEnumerator MyCoroutine()
    {
        //This is a coroutine
    }
}
复制代码