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");
    }
}
相关推荐
e***582337 分钟前
C#数据库操作系列---SqlSugar完结篇
网络·数据库·c#
IMPYLH38 分钟前
Lua 的 select 函数
java·开发语言·笔记·后端·junit·游戏引擎·lua
LateFrames41 分钟前
WinUI3 模拟 iPad 高级感动画:高斯模糊渐变 + 侧边划入
c#·winui3
code bean1 小时前
【C++ 】C++ 与 C#:using 关键字、命名空间及作用域解析符对比
开发语言·c++·c#
CAE虚拟与现实1 小时前
C# 调用 DLL为什么不像 C/C++调用 DLL 时需要lib库
开发语言·c++·c#·动态链接库·dll库·lib库
w2sfot2 小时前
将Minecraft游戏中的普通僵尸变为AI Zombie
游戏
民乐团扒谱机2 小时前
【微实验】携程评论C#爬取实战:突破JavaScript动态加载与反爬虫机制
大数据·开发语言·javascript·爬虫·c#
jtymyxmz2 小时前
《Unity shader》10.1.5 菲涅尔反射
unity·游戏引擎
lingggggaaaa2 小时前
免杀对抗——C2远控篇&PowerShell&C#&对抗AV-EDR&停用AMSI接口&阻断ETW跟踪&调用
c语言·开发语言·c++·学习·安全·c#·免杀对抗