zoukankan      html  css  js  c++  java
  • Unity 协程等待对象的生命周期

      Unity系统提供的协程等待有下面几个 : 

        yield return new WaitForFixedUpdate();
        yield return new WaitForEndOfFrame();
        yield return new WaitForSeconds(1.0f);
        yield return new WaitForSecondsRealtime(1.0f);

      一般情况下我们对协程的生命周期不是很关心, 因为是异步模式的 ( 虽然它不是异步的 ), 不过对于一个需要返回的等待对象, Unity 提供的是一个 class 对象, 比如一个循环等待的协程, 它就会产生很多的 GC 对象, 像下面这样 : 

        IEnumerator TestCoroutine1()
        {
            while(true)
            {
                // ......
                yield return new WaitForEndOfFrame();
                // ......
            }
        }

      而它又只是一个对象, 没有附带其它信息, 那么这个东西其实是可以复用的, 直接给它一个静态对象也是一样的 :

        public static readonly WaitForEndOfFrame WaitForEndOfFrame = new WaitForEndOfFrame();
        IEnumerator TestCoroutine1()
        {
            while(true)
            {
                yield return WaitForEndOfFrame;
                Debug.Log(Time.frameCount);
            }
        }

      然后很多人发现对于 WaitForEndOfFrame 其实返回的对象是空时 ( null ), 得到的结果也一样, 可是其实他们执行代码所在的生命周期是不同的, 可以看看下面的测试结果 : 

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Test : MonoBehaviour
    {
        int id = 0;
    
        void Awake()
        {
            StartCoroutine(TestCoroutine());
        }
    
        void Update()
        {
            Debug.Log("Update :: " + id++);
        }
    
        void LateUpdate()
        {
            Debug.Log("LateUpdate :: " + id++);
        }
    
        private void OnPostRender()
        {
            Debug.Log("OnPostRender :: " + id++);
        }
    
        IEnumerator TestCoroutine()
        {
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return null;
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }
    }

      这里使用 null 作为协程返回, 添加了 Update, LateUpdate, OnPostRender 等生命周期, 得到的结果如下 : 

      可见每次 yield 等待之后的代码调用都是在Update之后, LateUpdate之前调用的, 它插入的生命周期就在这里, 而 WaitForEndOfFrame 的就不同了, 就像描述的一样, 是在"一帧"之后才会调用 :

        IEnumerator TestCoroutine()
        {
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return new WaitForEndOfFrame();
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }

      可以看到插入的生命周期在相机完成渲染之后, 其实是在所有生命周期之后, 所以需要根据实际需求选择正确的返回, 比如你要获取当前帧相机的正确渲染结果, 就需要使用 WaitForEndOfFrame, 而你如果想要改变当前帧的渲染结果, 你就要使用 null 返回, 否则就变成获取到上一帧的渲染结果和改变下一帧的渲染了, 虽然影响不大...

      而 WaitForFixedUpdate 这个在物理帧里的显然使用的就很少了, 它跟逻辑跟渲染都不搭嘎.

      而 WaitForSeconds 跟 WaitForSecondsRealtime 有个决定性的不同, WaitForSeconds 跟 WaitForEndOfFrame 一样只是个简单对象, 而 WaitForSecondsRealtime 有自己的计时器 : 

      所以测试结果 WaitForSecondsRealtime 是无法使用全局对象的 : 

        IEnumerator TestCoroutine()
        {
            var WaitForSecondsRealtime = new WaitForSecondsRealtime(1.0f);
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return WaitForSecondsRealtime;
                Debug.Log(Time.realtimeSinceStartup);
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }

      它在第一次成功返回之后, 每帧都是成功返回, 没有意义...

      而 WaitForSeconds 还是正常的 : 

        IEnumerator TestCoroutine()
        {
            var WaitForSeconds = new WaitForSeconds(1.0f);
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return WaitForSeconds;
                Debug.Log(Time.realtimeSinceStartup);
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }

  • 相关阅读:
    关于SQLServer数据库中字段值为NULL,取出来该字段放在DataTable中,判断datatable中该字段值是否为NULL的三种方法
    关于web程序中使用KindEditor向数据库插入带有格式的数据时出现的问题
    使用再生龙对ubuntu16.04系统完全备份与还原
    mysql数据库操作指令汇总
    ubuntu安装supervisor以及使用supervisor启动.net core进程
    c#小数取整
    nuget.server搭建及实际测试
    mysql主从同步+mycat读写分离+.NET程序连接mycat代理
    EasyNVR-流媒体服务详解
    Js实现子窗体给父窗体的元素赋值
  • 原文地址:https://www.cnblogs.com/tiancaiwrk/p/13384015.html
Copyright © 2011-2022 走看看