zoukankan      html  css  js  c++  java
  • Unity3D协程的简单使用

      由于Unity 3D是单线程的,因此要想实现一些类似于多线程的功能,Unity实现了协程机制,要明确协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用。
      协程的定义
    IEnumerator test1(float waitTime) {//可变参数
        yield return null;//yield return表示协程暂停,将控制权交给Unity3D
    }
      开启协程
    public Coroutine StartCoroutine(IEnumerator routine);
    public Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value);
      停止协程
    public void StopCoroutine(string methodName);
    public void StopCoroutine(IEnumerator routine);
    //前者是使用方法名字符串,后者是使用方法的引用。
    //前者可以停止第一个名字为methodName的协程;后者可以准确地停止你引用的那个协程
    //第一种
    StartCoroutine("DoSomething");
    yield return new WaitForSeconds(2f);
    StopCoroutine("DoSomething");
    
    //第二种
    IEnumerator dosomething = DoSomething();
    StartCoroutine(dosomething);
    yield return new WaitForSeconds(2f);
    StopCoroutine(dosomething);
    
    //错误示例:并不能停止DoSomething,开启的协程和停止的协程不是同一个引用
    StartCoroutine(DoSomething());
    yield return new WaitForSeconds(2f);
    StopCoroutine(DoSomething());

      延时功能

    IEnumerator test2(float waitTime) {
        //等待waitTime秒之后执行后续代码
        yield return new WaitForSeconds(waitTime);
        //暂停协程直到下一次FixedUpdate时才会继续执行协程,WaitForFixedUpdate类暂停的时间取决于Unity3D的编辑器中的
        TimeManager的FixedTimestep中的值
        yield return new WaitForFixedUpdate();
        //等到所有摄像机和GUI被渲染完成后,再恢复协程的执行
        yield return new WaitForEndOfFrame();
    }
      使用WaitForEndOfFrame()延时截取当前屏幕的画面
    IEnumerator ScreenShotPNG() {
        yield return new WaitForEndOfFrame();
        int width = Screen.width;
        int height = Screen.height;
        Texture2D tex = new Texture2D(width,height,TextureFormat.RGB24,false);
        tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        tex.Apply();
        byte[] bytes = tex.EncodeToPNG();
        Destroy(tex);
        File.WriteAllBytes(Application.dataPath + "/../SaveScreen.png", bytes);
    }
    协程背后的迭代器原理
    C#代码:
    void Main(){
        IEnumerable<int> enumerable = TestStateChange();
        IEnumerator enumerator = enumerable.GetEnumerator();//此时迭代器状态由-2变为0
        bool hasNext = enumerator.MoveNext();//迭代器开始Running,迭代器状态由0变为-1
        Console.WriteLine("第一次调用MoveNext, 是否有数据" + hasNext); 
        hasNext = enumerator.MoveNext();
        Console.WriteLine("第二次调用MoveNext, 是否有数据" + hasNext);
        hasNext = enumerator.MoveNext();
        Console.WriteLine("第三次调用MoveNext, 是否有数据" + hasNext);
    }
    
    IEnumerable<int> TestStateChange() {
        Console.WriteLine("----我TestStateChange是第一行代码");
        Console.WriteLine("----我是第一个yield return前的代码");
        yield return 1;
        Console.WriteLine("----我是第一个yield return后的代码");
        Console.WriteLine("----我是第二个yield return前的代码");
        yield return 2;
        Console.WriteLine("----我是第二个yield return后的代码");
    }
    迭代器内部状态机的状态切换。
    -2状态:只有IEnumerable才有,表明在第一次调用GetEnumerator之前的状态
    -1状态:C#语言标准中规定的Running状态,表明此迭代器正在执行,当然,也会用于After状态
    0状态:Before状态,表明MoveNext()还一次都没有调用过
     
    WWW和协程
    public class HttpWrapper : MonoBehaviour {
        public void GET(string url, Action<WWW> onSuccess, Action<WWW> onFail = null) {
            WWW www = new WWW(url);
            StartCoroutine(WaitForResponse(www, onSuccess, onFail));
        }
    
        public void POST(string url, Dictionary<string, string> post, Action<WWW> onSuccess, Action<WWW> onFail = null)
        {
            WWWForm form = new WWWForm();
            foreach (KeyValuePair<string, string> arg in post)
            {
                form.AddField(arg.Key, arg.Value);
            }
            WWW www = new WWW(url, form);
            StartCoroutine(WaitForResponse(www, onSuccess, onFail));
        }
        IEnumerator WaitForResponse(WWW www, Action<WWW> onSuccess, Action<WWW> onFail = null) {
            yield return www;
            if (www.error == null)
            {
                onSuccess(www);
            }
            else {
                if (onFail != null) {
                    onFail(www);
                }
            }
        }
    }
  • 相关阅读:
    关于一个单机游戏发行的一些见解
    怎么租借电话号码
    NUMA架构的优缺点
    Windows 安装PostgreSQL
    Oracle查询当前用户下的所有表及sqlplus 设置 列宽
    Xshell调整终端显示的最大行数(缓冲区)
    PostgreSQL 索引膨胀
    Linux 清空缓存
    load多个数据文件的yaml
    Linux LVM逻辑卷配置过程详解(创建,增加,减少,删除,卸载)
  • 原文地址:https://www.cnblogs.com/tqw1215/p/13388703.html
Copyright © 2011-2022 走看看