0x00 前言

在使用Unity的过程中,对协程仅仅知道怎样使用,但并不知道协程的内部机理,对于自己不清楚的部分就像一块大石压力心里。让自己感觉到担忧和不适。

这篇文章一探到底,彻底揭开协程的面纱,让大家在使用中不再有后顾之忧。

0x01 概念

协程是:程序组件来生成非抢占式多任务子函数,生成的子函数同意在程序里挂起和唤醒操作。

0x02 使用场景

通常协程能够非常方便实现延时操作。以及异步载入操作。以下是两个简单协程使用样例。

延时操作

// Use this for initialization
void Start () {
    StartCoroutine (Wait ());
}

IEnumerator Wait(){
    Debug.Log ("start time:" + Time.time);
    yield return new WaitForSeconds (1);
    Debug.Log ("time:" + Time.time);
    yield return new WaitForSeconds(2);
    Debug.Log ("time:" + Time.time);
}

异步载入资源

// Use this for initialization
void Start () {;
    System.Action<string> callBack = delegate(string text) {
        Debug.Log(text);
    };
    StartCoroutine (LoadRes (callBack));
}

IEnumerator LoadRes(System.Action<string> callBack){
    WWW www = new WWW ("http://www.baidu.com");
    yield return www;

    if (string.IsNullOrEmpty (www.error)) {
        callBack(www.text);
        Debug.Log("load success");
    }
    else{
        Debug.Log("load failed");
    }
}

0x03 原理

Unity里的协程通过定义一个返回 IEnumerator类型的函数。先来通过一个函数看看Unity都能返回那些类型:

IEnumerator Test(){
    yield return 2;     // 返回整数 
    yield return 4.2;   // 返回浮点数  
    yield return null;  // 返回null
    yield return new WaitForSeconds(1); // 返回instance
    yield return new WWW ("http://www.baidu.com"); // 返回instance
}

返回的类型有什么要求?整理一下Unity都实现了那些返回类型:
1、int类型,须要等待的帧数
2、float类型,须要等待的时间(秒)
3、null,等待一帧
4、break,结束协程
5、实例,必须有bool isDone()成员函数,等isDone返回true
6、IEnumerator,等IEnumerator实例的MoveNext()返回false

Unity的返回类型知道了,怎样捕获这些返回类型?来看IEnumerator怎样实现的?

public interface IEnumerator
{
    //
    // Properties
    //
    object Current
    {
        get;
    }

    //
    // Methods
    //
    bool MoveNext ();

    void Reset ();
}

通过研究IEnumerator接口,得到通过调用MoveNext。我们能够得到遍历全部yield返回的值,返回的值能够通过Current得到。每次调用MoveNext都会运行夹在yield中间的代码。

写个測试程序来验证我们的理论:

public class game_client : MonoBehaviour {

    // Use this for initialization
    void Start () {
        IEnumerator i = Test ();
        while (true) {
            if(!i.MoveNext()){
                break;
            }
            object cur = i.Current;
            if(cur != null)
                Debug.Log(cur.GetType());
            else
                Debug.Log("type is null");
        }
    }


    IEnumerator Test(){
        yield return 2;         
        yield return 4.2;
        yield return null;
        yield return new WaitForSeconds(1);
        yield return new WWW ("http://www.baidu.com");
    }
}

通过验证程序。能够得到yield返回的值。有了这些值,就能够实现自己的协程。

0x04 实现

设计接口:

class ScheduleCoroutine
{
    public void StartCoroutine(IEnumerator coroutine);
    public void StopCoroutine(IEnumerator coroutine);
    public void Update(int frame, float time);
}

设计数据结构:

class CoroutineNode{
    public IEnumerator itor;
    public string name;
    public int frame;
    public float time;
    public Object instance;
    public CoroutineNode pre;
    public CoroutineNode next;
}

详细实现代码,对于不同的项目需求,有不同的实现方式。这篇文章主要是探寻Unity协程的实现方式。

搞清楚原理后,在使用上就会更加得心应手。

0x05 參考

文章參考了非常多其它博文。感谢他们的付出。

在第一个參考链接里。有详细实现代码。


1、UnifyWiki
2、维基百科

posted on 2017-08-16 08:36  lxjshuju  阅读(621)  评论(0编辑  收藏  举报