unity coroutine calldelay定时器原理 — 在此基础上,进一步扩展自定义协同程序等待机制。

继承 UserTypeWait 即可实现自定义的协同程序等待事件,效果类似于 WaitForSecondsWWWLoadLevelAsync 等内置等待方式。注意:Loop 方法是同步写法;如果需要真正的异步执行,在内部用多线程包装即可 — 版本4已实现多线程方案(这也许是多核优化的一个思路)。版本3则是 lambda 写法。

总之,想怎么玩就怎么玩。

版本1:类写法1

using UnityEngine;
using System.Collections;
using System;

public class UserTypeWait
{
    public IEnumerator Wait()
    {
        while (Loop())
        {
            yield return null;
        }
    }
    public virtual bool Loop()
    {
        return false;
    }
}


public class WaitForTickCount50 : UserTypeWait
{
    public override bool Loop()
    {
        ++c;
        if (c > 50)
        {
            return false;
        }
        return true;
    }
    int c = 0;
}


public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Run1());
    }

    IEnumerator Run1()
    {
        Debug.LogError("1111111");
        yield return new WaitForTickCount50().Wait();

        Debug.LogError("2222222222");
    }

}

版本2:类写法2

using UnityEngine;
using System.Collections;
using System;

public class UserTypeWait:IEnumerator
{
    public bool MoveNext()
    {
        return Loop();
    }
    public void Reset()
    {
    }
  public  object Current
    {
        get
        {
            return null;
        }
    }
    public virtual bool Loop()
    {
        return true;
    }
}

public class WaitForTickCount50 : UserTypeWait
{
    public override bool Loop()
    {
        ++c;
        if (c > 50)
        {
            return false;
        }
        return true;
    }
    int c = 0;
}


public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Run1());
    }

    IEnumerator Run1()
    {
        Debug.LogError("1111111");
        yield return new WaitForTickCount50();
        Debug.LogError("2222222222");
    }

}

版本3:lambda 写法

using UnityEngine;
using System.Collections;
using System;

public class UserTypeWait : IEnumerator
{
    public bool MoveNext()
    {
        return Loop();
    }
    public void Reset()
    {
    }
    public object Current
    {
        get
        {
            return null;
        }
    }
    public virtual bool Loop()
    {
        return false;
    }
}
public delegate bool BoolFuncVoid();

public class WaitForLambada : UserTypeWait
{
    BoolFuncVoid cb;
    public WaitForLambada(BoolFuncVoid cb)
    {
        this.cb = cb;
    }
    public override bool Loop()
    {
        if (cb == null)
        {
            return false;
        }
        return cb();
    }
    int c = 0;
}


public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Run1());
    }

    IEnumerator Run1()
    {
        Debug.LogError("1111111");
        int c = 0;
        yield return new WaitForLambada(() =>
        {
            c++;
            if (c > 50) return false;
            return true;
        });
        Debug.LogError("2222222222");
    }

}

版本4:多线程写法

多线程写法在某种程度上实现了真正的异步:逻辑上是同步写法,代码却由独立线程执行,做到了"同步写法、异步执行"。多核优化也因此变得更简单,例如可以进一步添加 WaitForThreadJobGroup 这类并发组等待。

using UnityEngine;
using System.Collections;
using System;

public class UserTypeWait : IEnumerator
{
    public bool MoveNext()
    {
        return Loop();
    }
    public void Reset()
    {
    }
    public object Current
    {
        get
        {
            return null;
        }
    }
    public virtual bool Loop()
    {
        return false;
    }
}
public delegate bool BoolFuncVoid();
public delegate void VoidFuncVoid();
public class WaitForThreadJob : UserTypeWait
{
    bool isDone = false;
    public override bool Loop()
    {
        return !isDone;
    }
    System.Threading.Mutex locker = new System.Threading.Mutex();
    public WaitForThreadJob(VoidFuncVoid job)
    {
        thread = new System.Threading.Thread(new System.Threading.ThreadStart(() =>
            {
                job();
                locker.WaitOne();
                isDone = true;
                locker.ReleaseMutex();
            }));
        thread.Start();
    }
    System.Threading.Thread thread;
}

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Run1());
    }

    IEnumerator Run1()
    {
        Debug.LogError("1111111");
        int c = 0;
        yield return new WaitForThreadJob(() =>
        {
            for (int i = 0; i < 3000000; i++)
            {
                Vector3.Distance(Vector3.zero, Vector3.one);
                Vector3.Distance(Vector3.zero, Vector3.one);
                Vector3.Distance(Vector3.zero, Vector3.one);
                Vector3.Distance(Vector3.zero, Vector3.one);
                Vector3.Distance(Vector3.zero, Vector3.one);
                Vector3.Distance(Vector3.zero, Vector3.one);
                Vector3.Distance(Vector3.zero, Vector3.one);
                Vector3.Distance(Vector3.zero, Vector3.one);
            }
        });
        Debug.LogError("2222222222");
    }

}

Unity 内置了类似功能的等待类:WaitWhileWaitUntilCustomYieldInstruction