Unity3D协程的简单使用

  由于Unity 3D是单线程的,因此要想实现一些类似于多线程的功能,Unity实现了协程机制,要明确协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用。
  协程的定义
IEnumerator test1(float waitTime) {//可变参数
    yield return null;//yield return表示协程暂停,将控制权交给Unity3D
}
  开启协程
public Coroutine StartCoroutine(IEnumerator routine);
public Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value);
  停止协程
public void StopCoroutine(string methodName);
public void StopCoroutine(IEnumerator routine);
//前者是使用方法名字符串,后者是使用方法的引用。
//前者可以停止第一个名字为methodName的协程;后者可以准确地停止你引用的那个协程
//第一种
StartCoroutine("DoSomething");
yield return new WaitForSeconds(2f);
StopCoroutine("DoSomething");

//第二种
IEnumerator dosomething = DoSomething();
StartCoroutine(dosomething);
yield return new WaitForSeconds(2f);
StopCoroutine(dosomething);

//错误示例:并不能停止DoSomething,开启的协程和停止的协程不是同一个引用
StartCoroutine(DoSomething());
yield return new WaitForSeconds(2f);
StopCoroutine(DoSomething());

  延时功能

IEnumerator test2(float waitTime) {
    //等待waitTime秒之后执行后续代码
    yield return new WaitForSeconds(waitTime);
    //暂停协程直到下一次FixedUpdate时才会继续执行协程,WaitForFixedUpdate类暂停的时间取决于Unity3D的编辑器中的
    TimeManager的FixedTimestep中的值
    yield return new WaitForFixedUpdate();
    //等到所有摄像机和GUI被渲染完成后,再恢复协程的执行
    yield return new WaitForEndOfFrame();
}
  使用WaitForEndOfFrame()延时截取当前屏幕的画面
IEnumerator ScreenShotPNG() {
    yield return new WaitForEndOfFrame();
    int width = Screen.width;
    int height = Screen.height;
    Texture2D tex = new Texture2D(width,height,TextureFormat.RGB24,false);
    tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
    tex.Apply();
    byte[] bytes = tex.EncodeToPNG();
    Destroy(tex);
    File.WriteAllBytes(Application.dataPath + "/../SaveScreen.png", bytes);
}
协程背后的迭代器原理
C#代码:
void Main(){
    IEnumerable<int> enumerable = TestStateChange();
    IEnumerator enumerator = enumerable.GetEnumerator();//此时迭代器状态由-2变为0
    bool hasNext = enumerator.MoveNext();//迭代器开始Running,迭代器状态由0变为-1
    Console.WriteLine("第一次调用MoveNext, 是否有数据" + hasNext); 
    hasNext = enumerator.MoveNext();
    Console.WriteLine("第二次调用MoveNext, 是否有数据" + hasNext);
    hasNext = enumerator.MoveNext();
    Console.WriteLine("第三次调用MoveNext, 是否有数据" + hasNext);
}

IEnumerable<int> TestStateChange() {
    Console.WriteLine("----我TestStateChange是第一行代码");
    Console.WriteLine("----我是第一个yield return前的代码");
    yield return 1;
    Console.WriteLine("----我是第一个yield return后的代码");
    Console.WriteLine("----我是第二个yield return前的代码");
    yield return 2;
    Console.WriteLine("----我是第二个yield return后的代码");
}
迭代器内部状态机的状态切换。
-2状态:只有IEnumerable才有,表明在第一次调用GetEnumerator之前的状态
-1状态:C#语言标准中规定的Running状态,表明此迭代器正在执行,当然,也会用于After状态
0状态:Before状态,表明MoveNext()还一次都没有调用过
 
WWW和协程
public class HttpWrapper : MonoBehaviour {
    public void GET(string url, Action<WWW> onSuccess, Action<WWW> onFail = null) {
        WWW www = new WWW(url);
        StartCoroutine(WaitForResponse(www, onSuccess, onFail));
    }

    public void POST(string url, Dictionary<string, string> post, Action<WWW> onSuccess, Action<WWW> onFail = null)
    {
        WWWForm form = new WWWForm();
        foreach (KeyValuePair<string, string> arg in post)
        {
            form.AddField(arg.Key, arg.Value);
        }
        WWW www = new WWW(url, form);
        StartCoroutine(WaitForResponse(www, onSuccess, onFail));
    }
    IEnumerator WaitForResponse(WWW www, Action<WWW> onSuccess, Action<WWW> onFail = null) {
        yield return www;
        if (www.error == null)
        {
            onSuccess(www);
        }
        else {
            if (onFail != null) {
                onFail(www);
            }
        }
    }
}
原文地址:https://www.cnblogs.com/tqw1215/p/13388703.html