[Unity基础]对Coroutine的一些理解

相关链接:

http://dsqiu.iteye.com/blog/2029701

http://www.cocos2dev.com/?p=496

http://7dot9.com/?p=605

http://7dot9.com/?paged=2


开启与关闭协程:

using UnityEngine;
using System.Collections;

public class TestCoroutine : MonoBehaviour {

	void Start () 
    {
        StartCoroutine("PrintA");//最多只能传递一个参数,并且性能消耗会更大一点
        //StopCoroutine("PrintA");

        IEnumerator b = PrintB();
        StartCoroutine(b);
        //StopCoroutine(b);
        //StopCoroutine(PrintB());//不能关闭

        //StopAllCoroutines();//只能关闭这个脚本的协程
	}

    IEnumerator PrintA()
    {
        yield return new WaitForSeconds(1);
        print("A");
    }

    IEnumerator PrintB()
    {
        yield return new WaitForSeconds(1);
        print("B");
    }
}


using UnityEngine;
using System.Collections;

public class TestCoroutine2 : MonoBehaviour {

	void Start () 
    {
        //StartCoroutine(PrintC());
        //gameObject.SetActive(false);//可以关闭协程

        StartCoroutine(PrintD());
        this.enabled = false;//不可以关闭协程
	}

    IEnumerator PrintC()
    {
        yield return new WaitForSeconds(1);
        print("C");
    }

    IEnumerator PrintD()
    {
        yield return new WaitForSeconds(1);
        print("D");
    }
}

嵌套协程:

using UnityEngine;
using System.Collections;

//yield return 代码段返回 0 或者 null 的意思就是告诉 Unity 等下一帧再从这里开始执行这个方法
//在 Wait() 方法成功执行返回之前不继续执行 SaySomeThings() 方法中的代码,
//等到 Wait() 方法执行结束之后再继续执行
public class TimerExample : MonoBehaviour {

    void Start()
    {
        StartCoroutine(SaySomeThings());
    }

    //Say some messages separated by time
    IEnumerator SaySomeThings()
    {
        Debug.Log("The routine has started");
        yield return StartCoroutine(Wait(1.0f));
        Debug.Log("1 second has passed since the last message");
        yield return StartCoroutine(Wait(2.5f));
        Debug.Log("2.5 seconds have passed since the last message");
    }

    //Our wait function
    IEnumerator Wait(float duration)
    {
        for (float timer = 0; timer < duration; timer += Time.deltaTime)
            yield return 0;
    }
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

一、通过设置MonoBehaviour脚本的enabled对协程是没有影响的,但如果 gameObject.SetActive(false) 则已经启动的协程则完全停止了,即使在Inspector把gameObject 激活还是没有继续执行。也就说协程虽然是在MonoBehvaviour启动的(StartCoroutine)但是协程函数的地位完全是跟MonoBehaviour是一个层次的,不受MonoBehaviour的状态影响,但跟MonoBehaviour脚本一样受gameObject 控制,也应该是和MonoBehaviour脚本一样每帧“轮询” yield 的条件是否满足。那么,如果我们即想让gameObject隐藏掉,但又不想那个gameObject上的mono脚本的协同程序被强制停止的话,我们就可以让其他mono去开启协程,例如Manager.Instance.StartCoroutine(Show());,让一个单例类的mono去开启协程,因为一般挂上Manager脚本的物体是不会被隐藏掉的。


二、yield 后面可以有的表达式:

       a) null - the coroutine executes the next time that it is eligible

       b) WaitForEndOfFrame - the coroutine executes on the frame, after all of the rendering and GUI is complete

       c) WaitForFixedUpdate - causes this coroutine to execute at the next physics step, after all physics is calculated

       d) WaitForSeconds - causes the coroutine not to execute for a given game time period

       e) WWW - waits for a web request to complete (resumes as if WaitForSeconds or null)

       f) Another coroutine - in which case the new coroutine will run to completion before the yielder is resumed

值得注意的是 WaitForSeconds()受Time.timeScale影响,当Time.timeScale = 0f 时,yield return new WaitForSecond(x) 将不会满足。

如果想忽略Time.timeScale影响,可以使用Time.realtimeSinceStartup,具体可以看这里:http://blog.csdn.net/Fredomyan/article/details/44132719


三、协程其实就是一个IEnumerator(迭代器),IEnumerator 接口有两个方法 Current 和 MoveNext() ,只有当MoveNext()返回 true时才可以访问 Current,否则会报错。迭代器方法运行到 yield return 语句时,会返回一个expression表达式并保留当前在代码中的位置。 当下次调用迭代器函数时执行从该位置重新启动。Unity在每帧做的工作就是:调用 协程(迭代器)MoveNext() 方法,如果返回 true ,就从当前位置继续往下执行。


四、


  • 如果你想在多个脚本中访问到某个 Coroutine,你只需要将 Coroutine 方法声明为静态的就可以了;
  • 尽管这货看起来很像多线程的玩意儿,但实际上 Coroutine 并不是多线程的,它们跟你的脚本运行在同一个线程中;
  • 如果你的方法需要进行大量的计算,那么你可以考虑使用 Coroutine 来分步完成它;
  • IEnumerator 方法不能有 ref 或 out 的参数,但是可以通过引用传入;

你可能感兴趣的:(coroutine)