Unity中自定义协程的实现

VCoroutine

Avalon712/VCoroutine: C# Coroutinehttps://github.com/Avalon712/VCoroutine

功能介绍

  1. 协程不依赖Unity的MonoBehaviour,内部自己管理协程的运行,你可以在任意地方开启一个协程(Run)、暂停一个协程(Stop,注:与Unity的Stop不一样的是,Stop不会杀死协程,你仍然可以通过Resume来恢复他的执行),恢复协程运行(Resume)、杀死一个协程(Kill);
  2. 支持yield return Task,只有异步任务完成后才会继续执行后续步骤;
  3. 可以设置依赖关系,当协程A的运行需要协程B、C都运行玩时才能执行,同时协程B、C的运行都互相不依赖,只有等待B、C都完成后协程A才会开始执行(与Unity中的Job System中的任务调度依赖关系原理一致);
  4. 可以自定义扩展,你可以扩展yield return类型的处理方式,以及为每个协程的运行单独设置yield处理器上下文对象;

安装方式

通过PackManager选中add package from git URL即可。

使用举例

1、对Unity内置的yield指令全部支持

cs 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using CysharpCoroutine;

public sealed class FuncTest : MonoBehaviour
{
    void Start()
    {
        TestVCoroutine().RunAsCoroutine();
    }
    
    private IEnumerator TestVCoroutine()
    {
        Debug.Log($"{nameof(TestVCoroutine)} Start");

        yield return new WaitForEndOfFrame();
        
        print(VCoroutine.Environment.ToString());
        
        int i = 0;
        while (++i < 10)
        {
            yield return null;
            print(VCoroutine.Environment.ToString());
        }
        
        yield return new WaitForFixedUpdate();
        
        print(VCoroutine.Environment.ToString());
        
        yield return new WaitUntil(() => ++i >= 30);
        
        Debug.Log(i);
        
        yield return new WaitWhile(() => ++i >= 50);
        
        Debug.Log(i);
        
        yield return new Func<bool>(() => ++i >= 100);
        
        Debug.Log(i);
        
        UnityWebRequest request = UnityWebRequest.Get("https://www.baidu.com");
        yield return request.SendWebRequest();
        
        print(request.downloadHandler.text);
        
        yield return Task.Run(() => { while (++i <= 100000) { } });
        
        Debug.Log(i);
        
        Debug.Log("WaitForSecondsRealtime Start");
        yield return new WaitForSecondsRealtime(3);
        Debug.Log("WaitForSecondsRealtime End");
        
        yield return TestVCoroutine2();
        
        yield return TestVCoroutine3(); //支持泛型
        
        Debug.Log("WaitForSeconds Start");
        yield return new WaitForSeconds(5); 
        Debug.Log("WaitForSeconds End");
        
        Debug.Log($"{nameof(TestVCoroutine)} End");
    }

    private IEnumerator TestVCoroutine2()
    {
        Debug.Log($"{nameof(TestVCoroutine2)} Start");
        yield return new WaitForSecondsRealtime(3);
        Debug.Log($"{nameof(TestVCoroutine2)} End");
    }
    
    private IEnumerator<Func<bool>> TestVCoroutine3()
    {
        int i = 0;
        Debug.Log($"{nameof(TestVCoroutine3)} Start");
        yield return () => ++i >= 100;
        Debug.Log(i);
        Debug.Log($"{nameof(TestVCoroutine3)} End");
    }
}

2、自定义扩展

cs 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using CysharpCoroutine;

public sealed class ExtensionTest : MonoBehaviour
{
    /// <summary>
    /// 创建一个自定义的处理器上下文,处理定时回调功能
    /// </summary>
    private readonly CoroutineYieldHandleContext _timerYieldHandlerContext = new CoroutineYieldHandleContext(new List<YieldHandler>(){new  YieldFloat()});
    
    private void Awake()
    {
        CoroutineYieldHandleContext.RegisterHandlerToDefaultContext(new YieldFloat()); //注册到默认的yield处理器上下文中
    }

    void Start()
    {
        TestWaitTime().RunAsCoroutine(); 
        TestTimer().RunAsCoroutine(_timerYieldHandlerContext); //使用自定义的处理器上下文处理协程的返回类型
    }

    IEnumerator TestWaitTime()
    {
        print("TestWaitTime Start");
        yield return 5f; //等待5秒
        print("TestWaitTime End");
    }

    IEnumerator TestTimer()
    {
        yield return 10f; //等待10秒后再开始执行,默认延时效果
        
        print("TestTimer Start");
        yield return 1f;
        print("TestTimer End");
    }

    /// <summary>
    /// 当yield return float时表示等待指定的秒数
    /// </summary>
    private sealed class YieldFloat : YieldHandler
    {
        public override Type YieldType => typeof(float);
        
        protected override bool HandleYield(VCoroutine.CoroutineRecorder recorder)
        {
            float seconds = (float)recorder.Yield - Time.deltaTime;
            recorder.Yield = seconds;
            return seconds <= 0;
        }
    }
}

3、依赖队列

cs 复制代码
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using CysharpCoroutine;

public sealed class DependencyTest : MonoBehaviour
{
    void Start()
    {
        /*
         依赖拓扑图
         A
         |----B
         |    |----C
         |    |    |----F
         |    |----E
         |----D
         */
        CoroutineID a = VCoroutine.Run(A());
        CoroutineID b = VCoroutine.Run(B());
        CoroutineID c = VCoroutine.Run(C());
        CoroutineID d = VCoroutine.Run(D());
        CoroutineID e = VCoroutine.Run(E());
        CoroutineID f = VCoroutine.Run(F());
        VCoroutine.CombineDependencies(a, true, b, d);
        VCoroutine.CombineDependencies(b, true, c, e);
        VCoroutine.CombineDependency(c,f);
        // VCoroutine.CombineDependency(f, a, false); //循环依赖,没有检测循环依赖,会导致所有依赖A的协程都无法运行
    }

    IEnumerator A()
    {
        print("A Start");
        yield return new WaitForSeconds(3);
        print("A End");
    }
        
    IEnumerator B()
    {
        print("B Start");
        yield return new WaitForSeconds(3);
        print("B End");
    }
        
    IEnumerator C()
    {
        print("C Start");
        yield return Task.Delay(3000);
        print("C End");
    }
        
    IEnumerator D()
    {
        print("D Start");
        UnityWebRequest request = UnityWebRequest.Get("https://www.baidu.com");
        yield return request.SendWebRequest();
        print("D End");
    }
        
    IEnumerator E()
    {
        print("E Start");
        ResourceRequest request = Resources.LoadAsync<GameObject>("Res");
        yield return request;
        Instantiate(request.asset);
        print("E End");
    }
    
    IEnumerator F()
    {
        print("F Start");
        yield return new WaitForFixedUpdate();
        print("F End");
    }
}
相关推荐
游乐码23 分钟前
Unity基础(十二)资源异步加载
unity·游戏引擎
weixin_424294672 小时前
程序不知道写在了什么位置???
unity
leo__5202 小时前
C# 虚拟键盘(软键盘)实现
单片机·c#·计算机外设
weixin_441940012 小时前
vuforia ar unity实验教程
unity·游戏引擎·ar
周杰伦fans4 小时前
AutoCAD C# 二次开发:如何精确监听工作空间切换事件
前端·c#
用户3721574261354 小时前
如何使用 C# 自动调整 Excel 行高和列宽
c#
妙为4 小时前
unreal engine5(UE5)中使用Rider
ue5·游戏引擎·虚幻·rider
AI导出鸭PC端4 小时前
智谱清言怎么生成word文档?AI导出鸭终结乱码烦恼
人工智能·ai·c#·word·豆包·ai导出鸭
wjql26 小时前
归环艾丽卡是谁 归环艾丽卡角色介绍
游戏
IpdataCloud6 小时前
遭遇DDoS攻击后如何快速分析攻击源?用IP离线库+威胁情报定位异常IP
网络·tcp/ip·游戏·智能路由器·ddos