99国产欧美另娄久久久精品_国内自拍农村少妇在线观看_久久亚洲道色宗和久久_日本aⅴ大伊香蕉精品视频_亚洲国产欧美日韩欧美特级_日本视频免费在线观看

  • 您的位置:首頁 > 新聞動態(tài) > Unity3D

    Unity3D協(xié)程Coroutine解析

    2019/1/9??????點擊:

    本文只是從Unity的角度去分析理解協(xié)程的內(nèi)部運行原理,而不是從C#底層的語法實現(xiàn)來介紹(后續(xù)有需要再進行介紹),一共分為三部分:

    1. 線程(Thread)和協(xié)程(Coroutine)

    使用協(xié)程的作用一共有兩點:1)延時(等待)一段時間執(zhí)行代碼;2)等某個操作完成之后再執(zhí)行后面的代碼??偨Y(jié)起來就是一句話:控制代碼在特定的時機執(zhí)行。 很多初學(xué)者,都會下意識地覺得協(xié)程是異步執(zhí)行的,都會覺得協(xié)程是C# 線程的替代品,是Unity不使用線程的解決方案。 所以首先,請你牢記:協(xié)程不是線程,也不是異步執(zhí)行的。協(xié)程和 MonoBehaviour 的 Update函數(shù)一樣也是在MainThread中執(zhí)行的。使用協(xié)程你不用考慮同步和鎖的問題。

    2. Unity中協(xié)程的執(zhí)行原理

    UnityGems.com給出了協(xié)程的定義: A coroutine is a function that is executed partially and, presuming suitable conditions are met, will be resumed at some point in the future until its work is done. 即協(xié)程是一個分部執(zhí)行,遇到條件(yield return 語句)會掛起,直到條件滿足才會被喚醒繼續(xù)執(zhí)行后面的代碼。 Unity在每一幀(Frame)都會去處理對象上的協(xié)程。Unity主要是在Update后去處理協(xié)程(檢查協(xié)程的條件是否滿足),但也有寫特例: 從上圖的剖析就明白,協(xié)程跟Update()其實一樣的,都是Unity每幀對會去處理的函數(shù)(如果有的話)。如果MonoBehaviour 是處于激活(active)狀態(tài)的而且yield的條件滿足,就會協(xié)程方法的后面代碼。還可以發(fā)現(xiàn):如果在一個對象的前期調(diào)用協(xié)程,協(xié)程會立即運行到第一個 yield return 語句處,如果是 yield return null ,就會在同一幀再次被喚醒。如果沒有考慮這個細(xì)節(jié)就會出現(xiàn)一些奇怪的問題『1』。 『1』注 圖和結(jié)論都是從UnityGems.com 上得來的,經(jīng)過下面的驗證發(fā)現(xiàn)與實際不符,D.S.Qiu用的是Unity 4.3.4f1 進行測試的。 經(jīng)過測試驗證,協(xié)程至少是每幀的LateUpdate()后去運行。

    下面使用 yield return new WaitForSeconds(1f); 在Start,Update 和 LateUpdate 中分別進行測試:

    using UnityEngine;
    using System.Collections;
    
    public class TestCoroutine : MonoBehaviour {
    
        private bool isStartCall = false;  //Makesure Update() and LateUpdate() Log only once
        private bool isUpdateCall = false;
        private bool isLateUpdateCall = false;
        // Use this for initialization
        void Start () {
            if (!isStartCall)
            {
                Debug.Log("Start Call Begin");
                StartCoroutine(StartCoutine());
                Debug.Log("Start Call End");
                isStartCall = true;
            }
    
        }
        IEnumerator StartCoutine()
        {
    
            Debug.Log("This is Start Coroutine Call Before");
            yield return null;
            Debug.Log("This is Start Coroutine Call After");
    
        }
        // Update is called once per frame
        void Update () {
            if (!isUpdateCall)
            {
                Debug.Log("Update Call Begin");
                StartCoroutine(UpdateCoutine());
                Debug.Log("Update Call End");
                isUpdateCall = true;
            }
        }
        IEnumerator UpdateCoutine()
        {
            Debug.Log("This is Update Coroutine Call Before");
            yield return null;
            Debug.Log("This is Update Coroutine Call After");
        }
        void LateUpdate()
        {
            if (!isLateUpdateCall)
            {
                Debug.Log("LateUpdate Call Begin");
                StartCoroutine(LateCoutine());
                Debug.Log("LateUpdate Call End");
                isLateUpdateCall = true;
            }
        }
        IEnumerator LateCoutine()
        {
            Debug.Log("This is Late Coroutine Call Before");
            yield return null;
            Debug.Log("This is Late Coroutine Call After");
        }
    }
    得到日志輸入結(jié)果如下:



    然后將yield return new WaitForSeconds(1f);改為 yield return null; 發(fā)現(xiàn)日志輸入結(jié)果和上面是一樣的,沒有出現(xiàn)上面說的情況.

    MonoBehaviour 沒有針對特定的協(xié)程提供Stop方法,其實不然,可以通過MonoBehaviour enabled = false 或者 gameObject.active = false 就可以停止協(xié)程的執(zhí)行『2』。

    經(jīng)過驗證,『2』的結(jié)論也是錯誤的,正確的結(jié)論是,MonoBehaviour.enabled = false 協(xié)程會照常運行,但 gameObject.SetActive(false) 后協(xié)程卻全部停止,即使在Inspector把 gameObject 激活還是沒有繼續(xù)執(zhí)行:

    using UnityEngine;
    using System.Collections;
    
    public class TestCoroutine : MonoBehaviour {
    
      private bool isStartCall = false;  //Makesure Update() and LateUpdate() Log only once
      private bool isUpdateCall = false;
      private bool isLateUpdateCall = false;
      // Use this for initialization
      void Start () {
        if (!isStartCall)
        {
          Debug.Log("Start Call Begin");
          StartCoroutine(StartCoutine());
          Debug.Log("Start Call End");
          isStartCall = true;
        }
    
      }
      IEnumerator StartCoutine()
      {
    
        Debug.Log("This is Start Coroutine Call Before");
        yield return new WaitForSeconds(1f);
        Debug.Log("This is Start Coroutine Call After");
    
      }
      // Update is called once per frame
      void Update () {
        if (!isUpdateCall)
        {
          Debug.Log("Update Call Begin");
          StartCoroutine(UpdateCoutine());
          Debug.Log("Update Call End");
          isUpdateCall = true;
          this.enabled = false;
          //this.gameObject.SetActive(false);
        }
      }
      IEnumerator UpdateCoutine()
      {
        Debug.Log("This is Update Coroutine Call Before");
        yield return new WaitForSeconds(1f);
        Debug.Log("This is Update Coroutine Call After");
        yield return new WaitForSeconds(1f);
        Debug.Log("This is Update Coroutine Call Second");
      }
      void LateUpdate()
      {
        if (!isLateUpdateCall)
        {
          Debug.Log("LateUpdate Call Begin");
          StartCoroutine(LateCoutine());
          Debug.Log("LateUpdate Call End");
          isLateUpdateCall = true;
    
        }
      }
      IEnumerator LateCoutine()
      {
        Debug.Log("This is Late Coroutine Call Before");
        yield return null;
        Debug.Log("This is Late Coroutine Call After");
      }
    }
    先在Update中調(diào)用 this.enabled = false; 得到的結(jié)果:



    然后把 this.enabled = false; 注釋掉,換成 this.gameObject.SetActive(false); 得到的結(jié)果如下:

    整理得到 :通過設(shè)置MonoBehaviour腳本的enabled對協(xié)程是沒有影響的,但如果 gameObject.SetActive(false) 則已經(jīng)啟動的協(xié)程則完全停止了,即使在Inspector把gameObject 激活還是沒有繼續(xù)執(zhí)行。也就說協(xié)程雖然是在MonoBehvaviour啟動的(StartCoroutine)但是協(xié)程函數(shù)的地位完全是跟MonoBehaviour是一個層次的,不受MonoBehaviour的狀態(tài)影響,但跟MonoBehaviour腳本一樣受gameObject 控制,也應(yīng)該是和MonoBehaviour腳本一樣每幀“輪詢” yield 的條件是否滿足。


    yield 后面可以有的表達(dá)式:

    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影響,當(dāng)Time.timeScale = 0f 時,yield return new WaitForSecond(x) 將不會滿足。

    3. IEnumerator & Coroutine

    協(xié)程其實就是一個IEnumerator(迭代器),IEnumerator 接口有兩個方法 Current 和 MoveNext() ,前面介紹的TaskManager就是利用者兩個方法對協(xié)程進行了管理,這里在介紹一個協(xié)程的交叉調(diào)用類 Hijack:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    
    [RequireComponent(typeof(Text))]
    public class HiJack : MonoBehaviour {
    
        //This will hold the counting up coroutine
        IEnumerator _countUp;
        //This will hold the counting down coroutine
        IEnumerator _countDown;
        //This is the coroutine we are currently
        //hijacking
        IEnumerator _current;
    
        //A value that will be updated by the coroutine
        //that is currently running
        int value = 0;
    
        void Start()
        {
            //Create our count up coroutine
            _countUp = CountUp();
            //Create our count down coroutine
            _countDown = CountDown();
            //Start our own coroutine for the hijack
            StartCoroutine(DoHijack());
        }
    
        void Update()
        {
            //Show the current value on the screen
            GetComponent().text = value.ToString ();
        }
    
        void OnGUI()
        {
            //Switch between the different functions
            if(GUILayout.Button("Switch functions"))
            {
                if(_current == _countUp)
                    _current = _countDown;
                else
                    _current = _countUp;
            }
        }
    
        IEnumerator DoHijack()
        {
            while(true)
            {
                //Check if we have a current coroutine and MoveNext on it if we do
                if(_current != null && _current.MoveNext())
                {
                    //Return whatever the coroutine yielded, so we will yield the
                    //same thing
                    yield return _current.Current;
                }
                else
                    //Otherwise wait for the next frame
                    yield return null;
            }
        }
    
        IEnumerator CountUp()
        {
            //We have a local increment so the routines
            //get independently faster depending on how
            //long they have been active
            float increment = 0;
            while(true)
            {
                //Exit if the Q button is pressed
                if(Input.GetKey(KeyCode.Q))
                    break;
                increment+=Time.deltaTime;
                value += Mathf.RoundToInt(increment);
                yield return null;
            }
        }
    
        IEnumerator CountDown()
        {
            float increment = 0f;
            while(true)
            {
                if(Input.GetKey(KeyCode.Q))
                    break;
                increment+=Time.deltaTime;
                value -= Mathf.RoundToInt(increment);
                //This coroutine returns a yield instruction
                yield return new WaitForSeconds(0.1f);
            }
        }
    }
    上面的代碼實現(xiàn)是兩個協(xié)程交替調(diào)用。



    主站蜘蛛池模板: 超碰在线公开97_成人水多啪啪片_国产精品裸体一区二区三区_久久免费在线_制服在线无码专区_91国偷自产一区二区三区蜜臀_伊人春色欧美_精品首页 | 91精品国产高清一区二区性色_99热国产在线_国产伦理久久久久久妇女_99热新网址_久久国产精品亚洲人一区二区三区_欧美老人巨大xxxx做受视频_人妻AⅤ无码专区_干干日日 | 欧美成人免费全部观看天天性色_免费视频xxx_在线观看日韩中文字幕_自拍偷拍av_偷摄私密养生馆少妇推油_免费一级a毛片免费观看_羞羞答答xxdd在线网站_成人免费视频网站在线看 | 亚洲中文无码永久免费_www私房写真在线观看_伊人无码一区二区三区_欧美精品在欧美一区二区_久久接色_欧美日韩精品一区_亚洲日本VA午夜在线影院_无码自拍一区 | 91cn国产在线_久久官网_日本爱爱网_亚洲女人久久久_天天操天天摸天天射_91蜜臀精品国产自偷在线_久久中文av_欧美精品videofree | 免费人成无码大片在线观看_久久九九影视_久久国产精品视频免费看_国产一级片每日更新_mm1313亚洲国产精品久久_在线a毛片_国产乱子伦视频大全_四虎黄色影院 | 一区二区三区无码视频免费福利_中文字幕不卡在线播放_2015成人永久免费视频_国产欧美一区二区精品婷婷_日韩第一页在线_国产高清第一页_欧美人与动牲交欧美精品_特级bbbbbbbbb视频 | 久久国产精品视频_色综合人人_国产网红主播精品一区_色综合精品久久久久久久_国产精品88久久久久久妇女_久久.com_午夜剧场大片亚洲欧洲一区_成人黄色777网 | 在线观看国产一区二区三区_99久久久99久久国产片鸭王_欧美日韩激情网_91精品国产色综合久久_国产精品网在线观看_丰满少妇被猛烈进入流水_色偷偷AV男人的天堂京东热_中文在线a | 国产中文字幕在线看_日韩av一区二区在线观看_国产日韩三级_91久久_中文字幕精品久久一区二区三区_夜夜撸网站_日韩精品一区二区三区水蜜桃_一本色综合久久 日韩第一页在线观看_看av在线_一区免费_日韩在线视频精品_91色爱_国产成人精品av在线_9区中文字幕在线_成熟丰满熟妇高潮XXXXX视频 | 精品国产一区二区三区久久_国产乱人伦真实精品视频_欧美肥胖老太bbw_一区二区三区在线视频_精品嫩草_欧美性xxxx视频_曰本黄色片_性XXXX中国HD | 日韩在线免费不卡_亚洲黄色小说视频_中日韩欧美中文字幕_国产免费一级大片_国产成人99_日欧一片内射VA在线影院_japanesemon乱_亚洲中文字幕无码久久 | 一级看片免费视频囗交_亚洲日韩在线中文字幕线路2区_国产一级片免费_久久精品a一级国产免视看成人_成人超碰在线观看_亚洲香蕉视频综合在线_久久毛片免费观看_2019年中文字字幕在线看不卡 | 九九久久久久_国产一级毛片不卡视频_91福利视频在线观看_国产精品久久午夜夜伦鲁鲁_av激情_av无码国产精品色午夜_国产一区免费在线观看_亚洲国产成人精品无码区 | 在线观看国产日韩欧美_日韩午夜视频免费_国产精品美女视频免费午夜版_夜夜爱夜夜操_日韩素人_久久久九九_国产在线看片_成人黄网站片免费视频 | 成人性生交大全免费看_少妇熟女高潮流白浆_日韩亚洲国产中文字幕欧美_国内精品久久久久影院中国_97视频热人人精品免费_蜜桃国精产品二三三区视频_国产精品无码日韩字幕资不卡_印度妓女野外xxww | 国产国语性生话播放_国一级片_成人拍拍视频_色婷婷综合久久久久中文图片_av在线亚洲男人的天堂_在线观看麻豆国产成人AV在线播放_女人一级片_一区一区视频 www视频在线观看免费_五月天狠狠干_精精国产视频_黄色一二三区_精品视频国产_操人网址_成年人视频在线免费看_狠狠操操 | 偷拍亚洲综合_亚洲欧洲国产日韩_啦啦啦在线视频免费观看高清中文_夜夜骑综合_亚洲美女自拍视频_中日精品一色哟哟_老妇女色视频_99香蕉国产精品偷在线观看 | 久久亚洲色WWW成人_无码国内精品久久人_国产精品亚洲片在线观看不卡_亚洲狠狠婷婷久久久四季av_国产原厂视频在线观看_成人国产精品免费观看视频_国产精品一区二区在线蜜芽TV_131mm亚洲国产精品久久 | 宅男伊人_四虎2023_一级日韩一级欧美_人人做人人爽人人添_一本大道无码人妻精品专区_人妻少妇波多野结衣_偷偷做久久久久网站_丰满少妇2中文在线观看 | 国产又大又硬又粗_黄色一级片免费看_成年女人免费视频播放人_日日噜噜噜夜夜爽爽狠狠视频97_国产精品第100页_在线免费观看h视频_秀人顶级模特尤妮丝的最新视频_中文字幕在线观看亚洲日韩 | 麻豆蜜桃_欧美黑人巨大久久久精品一区小蓝_久久青草av_成年人xxxx_狠狠躁夜夜躁人人爽天天开心婷婷_午夜一区在线观看_青草网址_小视频在线看 | 四虎影院观看_日本久久高清视频_曰韩黄色片_欧美性受xxxx黑人x丫x性爽_伊人久久天堂_特级黄色毛片_国产丰满大波大屁股熟女_性受xxxx黑人xyx蜜桃 | 极品少妇xxxx精品少妇偷拍_91琪琪在线_日本高清视频一区二区三区四区_台湾性色hd性色av_日韩伦乱_天天综合精品_性一级片_极品白嫩粉嫩美女国产 | 成人网在线播放_亚洲熟妇国产熟妇肥婆_成人无码区免费视频_久久国产大片_好爽好大久久久级淫片毛片小说_忘忧草日本在线WWW日本_中国白嫩精品bbwbbw_亚洲熟妇av午夜无码不卡 | www.色日本_91xxx在线观看_91蜜桃在线观看_中国XVIDEOS厕所偷窥_cao榴_99热门精品一区二区三区无码_欧美最厉害的喷水VIDEOS_99这里有精品视频 | caoporm-超频在线视频_欧美欧美欧美欧美首页_国产精品18久久久久久首页狼_91丨porny丨_高潮av在线_一级空姐毛片_女教师の爆乳bd在线观看_丁香婷婷综合激情五月色 | 亚洲最新av网站_yy111111少妇影院_国产AV夜夜欢一区二区三区_成人1区2区_欧美日韩版_av中文无码乱人伦_亚洲精品深夜AV无码一区二区_国产麻豆 成人资源在线_无限动漫视频在线观看免费动漫_久久国产二区_美日韩一区二区_亚洲久久视频_少妇高潮呻吟在线观看_国产亚洲2021成人乱码_日本成人久久久 | 好男人资源在线观看视频_日韩在线不卡视频_俄罗斯小younv另类_伊人久久综合精品无码AV专区_国产一级精品片_久久亚洲成人av_黄污视频在线免费观看_日本一二区免费 | 国产三级久久久精品麻豆三级_黄色成年人国语版在线观看_国产gv在线观看受被做哭_伦理片一级片_免费三区_狠狠操导航_久久精品对白_操操综合网 | 欧美爆操_91精品天堂_一女三男做2爱A片免费_国产精品久久久久免费a∨_久久97超碰色中文字幕蜜芽_aaa一级毛片_www.嫩草_国产av一级毛片 | 欧美黄视频网站_亚洲三级黄色片_亚洲精品一区二区网址_在线sese_无码福利日韩神码福利片_在线亚洲无砖砖区免费_在线一区二区三区精品_青草青青在线视频 | 精品一区精品二区制服_av视在线_久久久综合久久_少妇的bbw性大片_免费理论_日操操夜操操_免费99精品国产自在在线_亚洲色图综合区 | 99精品偷拍视频一区二区三区_永久免费黄色_第一视角vk_日韩一级黄色大片_中文字幕高清视频_国产精品久久久久久久久绿色_婷婷久久久亚洲欧洲日产国码AV_国内精品久久久久精品 | 成人小视频在线观看免费_麻豆精品久久久久久中文字幕无码_国产成人麻豆精品午夜福利在线_精品成av人一区二区三区_影视先锋男人无码在线_青青草青娱乐在线_天操夜夜操_精品一区毛片 | 欧美精品激情_西出玉门40集全免费播放_国产性猛交粗暴力xxxx_av爱爱com_在线不卡免费av_国产精品揄拍100视频_精品亚洲国产专区在线观看_人成精品 | 国产视频手机在线观看_日韩av免费一区二区_成人性生交大片兜免费看r_又黄又硬又湿又刺激视频免费_久久久精品人妻久久影视_99国产精品欲a_国产成人啪精品视频免费网站_JAPANESE国产在线观看 | 欧美一区二区三区久久综合_久久久精彩_国产视频精品区_爱爱免费看_日韩精品视频三区_国产成人精品高清久久_亚洲综合视频在线播放_日韩欧美中文字幕视频 | 九九热免费在线_国产亚洲精品AAAA片在线播放_日本地区不卡一区二区三区搜索_亚洲欧美日韩一级_国产在线看片免费人成视频97_fc2在线中文字幕_一级日本_黄绝一级毛片 | 日本一级中文字幕久久久久久_特级做a爰片免费看一区_精品视频日韩_国产成人精选在线观看不卡_91夜夜蜜桃臀一区二区三区_久久久视频在线_一级毛片大片_自拍偷区亚洲国内自拍蜜臀 | 国产黄色免费观看_99精品久久久久中文字幕_夜夜躁狠狠躁日日躁202_中文字幕12页_亚洲精品乱码久久久久久麻豆不卡_91mv.cool在线观看_成人免费ā片在线观看_午夜视频h |