• Unity3D 协程的介绍和使用


    我是快乐的搬运工 http://blog.csdn.net/u011397120/article/details/61236055

    ---------------------------------------------------------------------- 分割线 xx --------------------------------------------------------------------------

    本文是个人对Unity协程的一些理解和总结.Unity协程长的有点像线程,但却不是线程.因为协程仍然是在主线程中执行,且在使用时不用考虑同步与锁的问题.协程只是控制代码等到特定的时机后再执行后续步骤.

    启动协程

    Unity 5.x中使用StartCoroutine方法开启协程,其方式有以下几种.

    //形式一 
    StartCoroutine(CustomCorutineFn()); 
     StartCoroutine(CustomCorutineFn(7));//向方法中传递参数 
    //形式二 
    StartCoroutine(“CustomCorutineFn”); 
    StartCoroutine(“CustomCorutineFn”,7);//向方法中传递参数
    

    以上两种形式都可开起当前MonoBehaviour对象的协程,注意:当你想停止MonoBehaviour对象中的某个协程时,开启与停止协程需要使用相同的形式,不可混合使用.
    协程中有多种等待方式,例如:等到FixedUpdate结束后才执行,代码如下.

        bool canExcute = true;
        void FixedUpdate()
        {
            if (canExcute)
            {
                Debug.Log("FixedUpdate" );
            }
        }
        IEnumerator Corutine_WaitForFixedUpdate()
        {
            yield return new WaitForFixedUpdate();
            Debug.Log(string .Format("====>{0}    time:{1}", 1, Time .time));
            yield return new WaitForFixedUpdate();
            Debug.Log(string .Format("====>{0}    time:{1}", 2, Time .time));
        }
    

    输出结果如下.

    官方文档Monobehaviour的函数执行顺序图,就对协程再次执行的时机做了很好的描述.

    以上只是一个示意图,详细信息请看官方文档.
    链接 https://docs.unity3d.com/Manual/ExecutionOrder.html

    yield null:协程将在下一帧所有脚本的Update执行之后,再继续执行. 
    yield WaitForSeconds:协程在延迟指定时间,且当前帧所有脚本的 Update全都执行结束后才继续执行. 
    yield WaitForFixedUpdate:协程在所有脚本的FixedUpdate执行之后,再继续执行. 
    yield WWW:协程在WWW下载资源完成后,再继续执行. 
    yield StartCoroutine:协程在指定协程执行结束后,再继续执行. 
    WaitForSecondsRealtime:与WaitForSeconds类似,但不受时间缩放影响. 
    WaitWhile:当返回条件为假时才执行后续步骤.
    

    协程的执行也会受到其他因素的影响,例如:当时间缩放值Time.timeScale被修改后,放大或者缩小.FixedUpdate 方法会受影响,则WaitForFixedUpdate也会跟着受影响;当Update方法中同步加载较大的对象时,WaitForSeconds所指定的时间就可能会与实际的时间不一致.所以在执行协程等待时,要视情况而定.

    多个gameObject对象开启协程,执行顺序又是如何呢?
    假如场景中存在A,B两个gameObject对象,均使用WaitForFixedUpdate方式等待,则等待执行的部分,会在A,B两个对象的FixedUpdate都执行结束后,才开始执行当前帧后续可执行的部分.源码如下:

        void Awake()
        {
            StartCoroutine(Corutine_WaitForFixedUpdate());
        }
        IEnumerator Corutine_WaitForFixedUpdate()
        {
            Debug.Log(string .Format("A : {0}", 0));
            yield return new WaitForFixedUpdate();
            Debug.Log(string .Format("A : {0}", 1));
        }
        bool canExcute = false;
        void FixedUpdate()
        {
            if (!canExcute)
            {
                canExcute = true;
                Debug.Log("A FixedUpdate" );
            }
        }
    

     执行后输出结果如下.

    停止协程

    在开发中可能会开启多个协程,如果你想停止其中某个协程,你可使用StopCoroutine.但在使用时,你需要注意一点,停止协程的方式要与开启协程的方式一致.StopCoroutine(“CustomCorutineFn”)必须与StartCoroutine(“CustomCorutineFn”)成对使用,与StartCoroutine(CustomCorutineFn())一起使用则完全无效.
    通过StopCoroutine的重载方法可知道,还有两种方式可停止协程.在此举个例子,如下:

        IEnumerator cor;
        void Awake()
        {
            //注意保存IEnumerator变量.
            cor = Corutine_WaitForFixedUpdate();
            StartCoroutine(cor);
            StartCoroutine(Corutine_Stop());
        }
        IEnumerator Corutine_WaitForFixedUpdate()
        {
            Debug.Log(string .Format("A : {0}", 0));
            yield return new WaitForEndOfFrame();
            Debug.Log(string .Format("A : {0}", 1));
        }
        IEnumerator Corutine_Stop()
        {
            yield return new WaitForFixedUpdate();
            //通过cor停止协程
            //而不是this.StopCoroutine(Corutine_WaitForFixedUpdate());
            this.StopCoroutine(cor);
        }
    

    如果想停止多个协程,可使用StopAllCoroutines方法,但这种方法只能停止当前MonoBehaviour类实例中所有协程.其他不受影响.
    如果想停止gameObject上所有脚本组件中的协程,禁用脚本组件是无法停止协程的,只需要禁用gameObject即可.

    如何用协程的输出10组计数(每组5次,每次1秒)?
    源码如下:

    using System.Collections;
    using UnityEngine;
    
    public class mCorutine : MonoBehaviour
    {
        public float time = 1;
        void Awake()
        {
            StartCoroutine(FirstLayerCorutine());
        }
        IEnumerator FirstLayerCorutine()
        {
            for (int i = 0; i < 10; i++)
            {
                Debug.Log(string .Format("第{0}组", i + 1));
                yield return StartCoroutine(SecondLayerCorutine());
            }
        }
        IEnumerator SecondLayerCorutine()
        {
            for (int i = 0; i < 5; i++)
            {
                Debug.Log(string .Format("{0}", i + 1));
                yield return new WaitForSeconds(time);
            }
        }
    }
    

    协程的使用还有很多要注意的地方,在这里分享一个关于协程运行时的监控和优化的链接.
    http://gulu-dev.com/post/perf_assist/2016-12-20-unity-coroutine-optimizing

  • 相关阅读:
    曾经写过一个感觉比较复杂的业务,大家看看是否能直接SQL解决呢?
    二分查找算法的起步判定优化
    在一个项目中,哪些中间件、框架、或者设计模式真的帮你解决了某些困惑和代码重构问题,这些是可以记录博客的点
    md工具
    判断python socket服务端有没有关闭的方法
    oracle 12.2.0.3(19c) rpm 安装
    宜昌电信服务器拨号自动断开自动重新拨号
    ubuntu安装音视频相关的包
    ubuntu vlc rtsp拉流推流失败
    sed批量更改pkgconfig
  • 原文地址:https://www.cnblogs.com/crazytomato/p/8178382.html
Copyright © 2020-2023  润新知