游戏人生
About Me
  • 你好
  • Math
    • Number
      • Float IEEE754对确定性的影响
      • Pairing Function及其用途
    • Vector and Matrix
      • TRS基础概念
      • LossyScale深入分析
    • Quatenion
      • FromToRotation实现细节
    • Lerp and Curve
      • Slerp球形插值
      • Bezier Curve为什么重要
      • Interpolation和Extrapolation实现细节
  • Programming
    • C#
      • 学习资料
      • C# struct灵魂拷问
      • CIL的世界:call和callvirt
      • .NET装箱拆箱机制
      • .NET垃圾回收机制
    • Go
      • 基础特性
      • 如何正确的判空interface
      • 如何用interface模拟多态
      • 如何定制json序列化
      • 如何安全在循环中删除元素
      • 如何安全关闭channel
      • 如何集成c++库(cgo+swig)
      • 如何性能测试(benchmark, pprof)
    • Lua
      • 基础特性
  • General Game Development
    • Game Engine
      • 学习资料
      • 关于游戏引擎的认知
    • Networking
      • 帧同步
      • 状态同步
      • 物理同步
    • Physics
      • PhysX基本概念
      • PhysX增加Scale支持
      • PhysX场景查询
      • PhysX碰撞检测
      • PhysX刚体动力学
      • PhysX角色控制器
      • PhysX接入项目工程
      • 物理同步
      • 物理破坏
    • Design Pattern
      • 常用设计模式
      • MVP 架构模式
      • ECS 架构模式
  • Unity
    • Runtime
      • Unity拥抱CoreCLR
      • 浅析Mono内存管理
    • UGUI
      • 浅析UGUI渲染机制
      • 浅析UGUI文本优化
      • 介绍若干UGUI实用技巧
    • Resource Management
      • 浅析Unity堆内存的分类和管理方式
      • 深入Unity资源
      • 深入Unity序列化
      • 深入Assetbundle机制
    • Async
      • 深入Unity协程
      • 介绍若干Unity协程实用技巧
      • 异步动作队列
    • Hot Reload
      • Unity+Xlua
      • Xlua Examples学习(一)
      • Xlua Examples学习(二)
    • Editor Extension
    • Performance
      • 浅析Unity Profiler
      • 介绍一个Overdraw分析工具
  • Platform
    • WebGL
  • Real-world Project
    • Souce Engine
    • DOOM3 BFG
Powered by GitBook
On this page
  • 基本使用
  • yield
  • 内置的YieldInstruction
  • 可返回值的协程
  • 嵌套协程
  • 可处理异常的协程
  1. Unity
  2. Async

介绍若干Unity协程实用技巧

Previous深入Unity协程Next异步动作队列

Last updated 3 years ago

基本使用

yield

  • yield break。中止协程中的后续操作。

  • yield return null/1/true/false。挂起协程,回到主函数逻辑,下一帧【执行游戏逻辑时】从挂起的位置继续。

  • yield return new WaitForSeconds(1.0f)。挂起协程,1s后【执行游戏逻辑时】从挂起的位置继续。

  • yield return new WaitForEndOfFrame()。挂起协程,这一帧的渲染结束【显示到屏幕之前】时从挂起的位置继续。

  • yield return StartCorotine(subCoroFunc());。嵌套协程。当【子协程完全执行完毕时 && 执行游戏逻辑时】从挂起的位置继续。嵌套协程的作用不大,只是看上去更有层次。

//type 1
IEnumerator CoroFunc1()
{
    yield return null;
}
//type 2 yield return type is limited to string
IEnumerator<string> CoroFunc2()
{
    yield return "hello";
}
//type 3 with param
IEnumerator<string> CoroFunc3(string str)
{
    yield return "hello" + str;
}
//type 4 return IEnumerable: not necessary.
IEnumberable CoroFunc4(int i)
{
    yield return null;
}

创建并开始协程:

//type 1 use anywhere inside a monobehaviour class
Coroutine coro = StartCoroutine(CoroFunc1());

//type 2 use inside a coroutine, unity automatically create a Coroutine, and call it next frame.
yield return CoroFunc1();

//type 3 just don't use it, very slow
Coroutine coro = StartCoroutine("CoroFunc4", 1);

停止协程:

StopCoroutine(coro);

内置的YieldInstruction

除了常用的WaitForSeconds,WaitForEndOfFrame等,以下同样继承自YieldInstruction的子类也有其便捷之处:

  • WaitUntil

  • WaitWhile

bool finishCondition = false;
yield return new WaitUntil(() => finishCondition)
//go on when finishCondition is true

可返回值的协程

有时会有这种需求:等待协程结束后,获取到yield return的结果。

//pseudocode
var retCode = yield return new XXX();
Print(retCode);
public class CoroutineWithData : CustomYieldInstruction
{
    public int retCode { get; private set; }
    private bool _finished = false;

    public void onFinished(bool isSucc)
    {
        _finished = true;
        retCode = isSucc ? 0 : -1;
    }

    //must override this
    public override bool keepWaiting
    {
        get
        {
            return !_finished;
        }
    }
}

//how to use:
public class main : MonoBehaviour {

    private IEnumerator Start()
    {
        CoroutineWithData coro = new CoroutineWithData();
        yield return coro;
        Debug.Log("retcode:" + coro.retCode);
    }
    //click btn to continue coro
    public void btnClickHandler()
    {
        coro.onFinished(true);
    }
}

嵌套协程

协程的嵌套使用不仅是为了更明了地组织逻辑代码,而且可以实现协程同步:

  • 同步、阻塞式(最基本用法)

IEnumerator A()
{
    yield return StartCoroutine(B());

    //wait for B() finishes
}
  • 同时进行

    IEnumerator A()
    {
      StartCoroutine(B());
    
      //execute at the same time
    }
  • 异步,阻塞式

    ```cs IEnumerator A() { Coroutine sub = StartCoroutine(B());

    //do sth at the same time

    yield return sub;

    //wait for B() finishes }

IEnumerator AA() { Coroutine sub1 = StartCoroutine(B()); Coroutine sub2 = StartCoroutine(B());

//do sth at the same time

yield return sub1;
yield return sub2;

//wait for all finishes

}

## 多态协程

```cs
//parent class:
protected virtual IEnumberator  DoSomething()
{
    yield return null;
}

//child class
protected override IEnumberator DoSomething()
{
    //you can call base like this:
    yield return StartCoroutine(base.DoSomething();

    //do something
}

可处理异常的协程

除了网络上给出的外,现在还可以利用CustomYieldInstruction来实现。

较早的实现方式
http://twistedoakstudios.com/blog/Post83_coroutines-more-than-you-want-to-know
Unity协程实用技巧
基本使用
内置的YieldInstruction
可返回值的协程
嵌套协程
多态协程
可处理异常的协程