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");
    }
}
相关推荐
锦瑟弦音3 小时前
微信小游戏分包(cocos自带分包)
笔记·游戏
六bring个六5 小时前
文件压缩处理(一)
开发语言·c#
ok406lhq11 小时前
unity游戏调用SDK支付返回游戏会出现画面移位的问题
android·游戏·unity·游戏引擎·sdk
superman超哥11 小时前
仓颉语言中字符串常用方法的深度剖析与工程实践
开发语言·后端·python·c#·仓颉
bugcome_com12 小时前
C# 中 ref 与 out 参数传递:核心区别与实战解析
c#
用户44884667106012 小时前
.NET 进阶 —— 深入理解线程(3)ThreadPool 与 Task 入门:从手动线程到池化任务的升级
c#·.net
ellis197012 小时前
toLua[八] main场景分析
unity·lua
CreasyChan12 小时前
unity四元数 - “处理旋转的大师”
unity·c#·游戏引擎
wuguan_12 小时前
C#索引器
c#·索引器
聪明努力的积极向上13 小时前
【设计】分批查询数据通用方法(基于接口 + 泛型 + 定点复制)
开发语言·设计模式·c#