• Unity 协程使用指南


    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、维基百科

  • 相关阅读:
    十分钟内学会:控制浏览器是否缓存网页状态
    编写 iPhone Friendly 的 Web 应用程序 (Part 7 多点触击)
    写个 JavaScript 异步调用框架 (Part 4 链式调用)
    拆分自然数:纯while实现 (Part 2 实现)
    诚聘 项目经理 & C++开发高手
    李天平:日常管理随笔一
    诚聘:.Net 软件工程师
    对 Enterprise Library 2.0 进一步封装: DbHelperSQL2
    李天平:无为而治&灯下黑
    累并快乐着!
  • 原文地址:https://www.cnblogs.com/fengju/p/6174280.html
Copyright © 2020-2023  润新知