当前位置: 首页 > news >正文

Unity实现自己的协程系统

为什么自己实现一套协程系统

        协程(Coroutine)是一个强大且灵活的工具,它可以帮助开发者处理异步任务,例如等待某些事件、处理逐帧更新等。在Unity中,协程通常通过IEnumerator来实现,这种机制允许代码在执行过程中暂停和恢复。

        然而,Unity原生的协程系统虽然简单易用,但在复杂场景下,例如管理多个协程、处理等待条件、暂停和恢复协程等,会显得力不从心。因此,我设计并实现了一个自定义的协程调度系统,旨在提供更强的控制、调度和扩展性。

系统结构概述

我的系统包括以下几个核心组件:

协程节点(CoroutineNode):用于表示一个协程的执行单元,负责管理协程的状态(暂停、完成)以及等待条件。

协程调度器(CoroutineScheduler):负责调度多个协程的执行顺序、暂停和恢复协程、移除完成的协程。

等待条件(WaitCondition):允许协程在特定条件下暂停执行,直到条件满足。

协程节点设计

协程节点是协程的封装体,主要负责:

维护协程的主体:即IEnumerator。

管理协程的状态:包括是否完成、是否暂停。

等待条件:协程可以通过等待特定条件来决定是否继续执行。

接口结构

/// <summary>
/// 一个协程节点的基础结构
/// </summary>
public interface ICoroutineNode
{/// <summary>/// 是否完成/// </summary>bool IsFinished { get; set; }/// <summary>/// 是否暂停/// </summary>bool IsPaused { get; set; }/// <summary>/// 枚举器,代表协程的主体/// </summary>IEnumerator Fiber { get; }/// <summary>/// 协程等待条件/// </summary>ICoroutineWaitCondition WaitCondition { get; }/// <summary>/// 判断协程是否需要等待/// </summary>/// <returns></returns>bool NeedWait();/// <summary>/// 添加一个等待条件/// </summary>/// <param name="condition"></param>void AddWaitCondition(ICoroutineWaitCondition condition);// 暂停协程void Pause();// 恢复协程void Resume();
}

具体实现

/// <summary>
/// 具体的协程节点实现
/// </summary>
public class CoroutineNode : ICoroutineNode
{// 协程主体(Fiber)public IEnumerator Fiber { get; private set; }// 是否完成public bool IsFinished { get; set; }// 是否暂停public bool IsPaused { get; set; }// 当前节点的等待条件private ICoroutineWaitCondition waitCondition = null;public ICoroutineWaitCondition WaitCondition => waitCondition;// 构造函数,传入一个协程(Fiber)public CoroutineNode(IEnumerator fiber){Fiber = fiber;IsFinished = false;IsPaused = false;}// 添加等待条件public void AddWaitCondition(ICoroutineWaitCondition condition) => waitCondition = condition;// 检查是否需要等待,决定协程是否可以继续执行public bool NeedWait() => waitCondition.keepWaiting;// 暂停等待条件public void Pause() => waitCondition.Pause();// 恢复等待条件   public void Resume() => waitCondition.Resume();
}

        协程节点可以灵活管理一个协程的生命周期,并与等待条件解耦,便于扩展和控制。

协程调度器设计

顺序调度器与并行调度器

我的设计中包含两种不同的协程调度器:

顺序调度器(CoroutineSchedulerOrder):按照协程的加入顺序,依次执行每个协程,前一个协程完成后,才开始下一个协程的执行。

并行调度器(CoroutineScheduler):允许多个协程并行执行,每帧都会更新所有未完成的协程。

在并行调度器中的协程,执行顺序不保证,所以不要修改同一份数据.

后续如果继续实现不同类型的调度器,可以轻松地改为工厂模式生产调度器

接口结构

/// <summary>
/// 一个协程调度器的基础结构
/// </summary>
public interface ICoroutineScheduler
{/// <summary>/// 剩余协程数量/// </summary>int CoroutineCount { get; }/// <summary>/// 向调度器中添加协程/// </summary>/// <param name="fiber">枚举器</param>/// <returns></returns>ICoroutineNode AddCoroutine(IEnumerator fiber);/// <summary>/// 暂停一个协程/// </summary>/// <param name="coroutine"></param>void PauseCoroutine(ICoroutineNode coroutine);/// <summary>/// 恢复一个协程/// </summary>/// <param name="coroutine"></param>void ResumeCoroutine(ICoroutineNode coroutine);/// <summary>/// 移除一个协程/// </summary>/// <param name="coroutine"></param>/// <returns></returns>ICoroutineNode RemoveCoroutine(ICoroutineNode coroutine);/// <summary>/// 移除全部协程/// </summary>void RemoveAllCoroutines();// 更新协程状态,在每帧调用void UpdateCoroutines();
}

具体实现

并行调度器
/// <summary>
/// 每帧会将列表的所有协程执行一遍,不保证顺序
/// </summary>
public class CoroutineScheduler : ICoroutineScheduler
{// 用于存储所有协程的队列private List<ICoroutineNode> coroutineList = new List<ICoroutineNode>();//被暂停的协程private HashSet<ICoroutineNode> frozenCoroutineHashSet = new HashSet<ICoroutineNode>();private List<ICoroutineNode> finishedCoroutines = new List<ICoroutineNode>();//所剩协程数量public int CoroutineCount { get => coroutineList.Count; }// 向调度器中添加协程public ICoroutineNode AddCoroutine(IEnumerator fiber){if (fiber == null){return null;}ICoroutineNode coroutine = new CoroutineNode(fiber); // 创建协程节点coroutineList.Add(coroutine); // 将节点加入队列return coroutine;}// 停止一个特定的协程,不影响其他协程public void PauseCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = true;}//恢复一个协程public void ResumeCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = false;}/// <summary>/// 移除一个协程,视为该协程完成了/// </summary>/// <param name="coroutine"></param>/// <returns></returns>public ICoroutineNode RemoveCoroutine(ICoroutineNode coroutine){coroutine.IsFinished = true;if (frozenCoroutineHashSet.Contains(coroutine)) frozenCoroutineHashSet.Remove(coroutine);return coroutine;}// 移除所有协程,视为已完成public void RemoveAllCoroutines(){foreach (var c in coroutineList) c.IsFinished = true;frozenCoroutineHashSet.Clear();}// 更新协程状态,在每帧调用public void UpdateCoroutines(){int queueSize = coroutineList.Count;if (queueSize == 0) return;foreach (var coroutine in coroutineList){//已完成协程移除列表if (coroutine.IsFinished){finishedCoroutines.Add(coroutine);continue;}//被暂停协程if (coroutine.IsPaused){if (frozenCoroutineHashSet.Contains(coroutine)) continue;if (coroutine.WaitCondition != null){coroutine.Pause();frozenCoroutineHashSet.Add(coroutine);}continue;}else if (frozenCoroutineHashSet.Contains(coroutine))//是否是被暂停过的协程要恢复{coroutine.Resume();frozenCoroutineHashSet.Remove(coroutine);}if (coroutine.WaitCondition == null){}else if (coroutine.NeedWait()) continue;MoveNextCoroutine(coroutine);}// 移除已经完成的协程foreach (var finished in finishedCoroutines){coroutineList.Remove(finished);}finishedCoroutines.Clear();}private void MoveNextCoroutine(ICoroutineNode coroutine){// 如果协程可以继续执行,调用 MoveNext() 继续执行协程if (coroutine.Fiber.MoveNext()){System.Object yieldCommand = coroutine.Fiber.Current; // 获取当前协程的返回值var coroutineWaitCondition = yieldCommand as ICoroutineWaitCondition;// 如果返回的是等待条件,添加等待条件到协程节点if (coroutineWaitCondition != null)coroutine.AddWaitCondition(coroutineWaitCondition);elsethrow new System.Exception("yield return type error");}else{coroutine.IsFinished = true; // 标记协程已完成finishedCoroutines.Add(coroutine);}}
}
顺序调度器
/// <summary>
/// 协程调度器,管理协程的生命周期和调度
/// 该调度器的协程有执行顺序,前一个协程彻底执行完,下一个协程才开始执行
/// </summary>
public class CoroutineSchedulerOrder : ICoroutineScheduler
{// 用于存储所有协程的队列private Queue<ICoroutineNode> coroutineQueue = new Queue<ICoroutineNode>();//被暂停协程private ICoroutineNode frozenCoroutineNodeOrder = null;//所剩协程数量public int CoroutineCount { get => coroutineQueue.Count; }// 向调度器中追加协程public ICoroutineNode AddCoroutine(IEnumerator fiber){if (fiber == null){return null;}ICoroutineNode coroutine = new CoroutineNode(fiber); // 创建协程节点coroutineQueue.Enqueue(coroutine); // 将节点加入队列return coroutine;}// 停止一个特定的协程,这将阻塞后续的协程public void PauseCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = true;}//恢复一个被暂停的协程public void ResumeCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = false;}// 移除一个协程,视为该协程完成了public ICoroutineNode RemoveCoroutine(ICoroutineNode coroutine){coroutine.IsFinished = true;if (frozenCoroutineNodeOrder == coroutine){frozenCoroutineNodeOrder = null;}var coroutineList = coroutineQueue.ToList();coroutineList.Remove(coroutine);coroutineQueue = new Queue<ICoroutineNode>(coroutineList);return coroutine;}// 移除所有协程,视为已完成public void RemoveAllCoroutines(){foreach (var c in coroutineQueue) c.IsFinished = true;frozenCoroutineNodeOrder = null;coroutineQueue.Clear();}// 更新协程状态,在每帧调用public void UpdateCoroutines(){int queueSize = coroutineQueue.Count;if (queueSize == 0) return;ICoroutineNode coroutine = coroutineQueue.Peek(); // 获取队首协程// 如果协程已完成,从队列中移除if (coroutine.IsFinished){coroutineQueue.Dequeue();return;}// 如果协程暂停,执行暂停操作,并跳过本帧处理if (coroutine.IsPaused){if (frozenCoroutineNodeOrder != null && frozenCoroutineNodeOrder == coroutine) return;if (coroutine.WaitCondition != null){coroutine.Pause();frozenCoroutineNodeOrder = coroutine; // 记录冻结的协程                }return;}else if (frozenCoroutineNodeOrder != null && frozenCoroutineNodeOrder == coroutine){coroutine.Resume(); // 如果之前被冻结,现在恢复协程frozenCoroutineNodeOrder = null;}if (coroutine.WaitCondition == null){//什么也不用做,走到MoveNextCoroutine进行初始化}else if (coroutine.NeedWait()) return; // 检查协程是否满足继续执行的条件MoveNextCoroutine(coroutine);}private void MoveNextCoroutine(ICoroutineNode coroutine){// 如果协程可以继续执行,调用 MoveNext() 继续执行协程if (coroutine.Fiber.MoveNext()){System.Object yieldCommand = coroutine.Fiber.Current; // 获取当前协程的返回值var coroutineWaitCondition = yieldCommand as ICoroutineWaitCondition;// 如果返回的是等待条件,添加等待条件到协程节点if (coroutineWaitCondition != null)coroutine.AddWaitCondition(coroutineWaitCondition);elsethrow new System.Exception("yield return type error");}else{coroutine.IsFinished = true; // 标记协程已完成coroutineQueue.Dequeue(); // 将完成的协程移出队列}}
}

等待条件设计

        为了增强协程的灵活性,我设计了可扩展等待条件,可以等待特定帧数、时间、或其他协程的完成。

        这里我在设计接口的时候和Unity提供的自定义协程接口保持一致,使用了同名的keepWaiting.所以实现自定义的等待条件的时候同时继承CustomYieldInstruction和ICoroutineWaitCondition并不会冲突,从而可以实现等待条件可以在两套协程系统中通用.

//
// 摘要:
//     Base class for custom yield instructions to suspend coroutines.
public abstract class CustomYieldInstruction : IEnumerator
{//// 摘要://     Indicates if coroutine should be kept suspended.public abstract bool keepWaiting { get; }public object Current => null;public bool MoveNext(){return keepWaiting;}public virtual void Reset(){}
}

接口结构

// 定义等待条件的结构,实现该接口自定义可 yield return的对象
public interface ICoroutineWaitCondition
{/// <summary>/// 判断是否需要继续等待(true则条件未满足继续等待)/// </summary>bool keepWaiting { get; }/// <summary>/// 被暂停时会调用一次/// </summary>void Pause();/// <summary>/// 被恢复时会调用一次/// </summary>void Resume();
}

具体实现

        这里我使用了结构体来实现等待条件,原因是简单的条件不需要额外使用内存,就像Unity原生协程也不继承CustomYieldInstruction一样(而是使用了YieldInstruction).你也可以使用类来实现复杂的条件,使用类来实现也可以同时继承CustomYieldInstruction和ICoroutineWaitCondition达到一个通用的效果,使用结构体则能节约内存.

//
// 摘要:
//     Suspends the coroutine execution for the given amount of seconds using scaled
//     time.
[StructLayout(LayoutKind.Sequential)]
[RequiredByNativeCode]
public sealed class WaitForSeconds : YieldInstruction
{internal float m_Seconds;//// 摘要://     Suspends the coroutine execution for the given amount of seconds using scaled//     time.//// 参数://   seconds://     Delay execution by the amount of time in seconds.public WaitForSeconds(float seconds){m_Seconds = seconds;}
}

#region 等待条件
// 等待帧
public struct WaitForFrameCondition : ICoroutineWaitCondition
{private int waitFrame; // 等待帧数bool ICoroutineWaitCondition.keepWaiting{get{waitFrame--;return waitFrame > 0;}}public WaitForFrameCondition(int frame){if (frame <= 0){throw new ArgumentException("Frame must be greater than 0.", nameof(frame));}waitFrame = frame;}// 无需实现void ICoroutineWaitCondition.Pause() { }// 无需实现void ICoroutineWaitCondition.Resume() { }
}// 等待时间
public struct WaitForTimeCondition : ICoroutineWaitCondition
{bool ICoroutineWaitCondition.keepWaiting{get{waitTime -= Time.deltaTime;return waitTime > 0;}}private float waitTime; // 等待时间public WaitForTimeCondition(float time){waitTime = time;}// 无需实现void ICoroutineWaitCondition.Pause() { }// 无需实现void ICoroutineWaitCondition.Resume() { }}// 等待其他协程完成的条件类
public struct WaitForCoroutineCondition : ICoroutineWaitCondition
{bool ICoroutineWaitCondition.keepWaiting{get{return !coroutine.IsFinished;}}private ICoroutineNode coroutine; // 被依赖的协程节点public WaitForCoroutineCondition(ICoroutineNode coroutine){this.coroutine = coroutine;}// 暂停依赖的协程void ICoroutineWaitCondition.Pause() => this.coroutine.Pause();// 恢复依赖的协程void ICoroutineWaitCondition.Resume() => this.coroutine.Resume();
}#endregion

示例代码

并行调度器示例

        通常我们会有多个调度器实例存在于多个非Mono实例中(比如数据层),多个调度器实例的方法在它们的表现层(继承Mono)或者一个全局的调度器的Update中执行UpdateCoroutines方法,将协程调度出去.

        下面的实例代码为方便没有这么做.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CoroutineSchedulerTest : MonoBehaviour
{CoroutineScheduler c=new CoroutineScheduler();// Start is called before the first frame updatevoid Start(){c.AddCoroutine(TestTime());var t = c.AddCoroutine(TestTime1());c.AddCoroutine(TestCoroutine(t));}// Update is called once per framevoid Update(){c.UpdateCoroutines();}IEnumerator TestTime(){yield return new WaitForTimeCondition(3);Debug.Log("等待三秒");}IEnumerator TestTime1(){yield return new WaitForTimeCondition(2);Debug.Log("等待两秒");}IEnumerator TestCoroutine(ICoroutineNode c){yield return new WaitForCoroutineCondition(c);Debug.Log("等待一个协程完成,这里我等待的协程是等待两秒的协程");}
}

顺序调度器示例

using UnityEngine;
using System.Collections;public class CoroutineSchedulerOrderTest : MonoBehaviour
{CoroutineSchedulerOrder coroutineSchedulerOrder = new CoroutineSchedulerOrder();private void Start(){coroutineSchedulerOrder.AddCoroutine(TestFrame());var t = coroutineSchedulerOrder.AddCoroutine(TestTime());coroutineSchedulerOrder.AddCoroutine(TestCoroutine(t));}private void Update(){coroutineSchedulerOrder.UpdateCoroutines();}IEnumerator TestFrame(){yield return new WaitForFrameCondition(1);Debug.Log("等待一帧");}IEnumerator TestTime(){yield return new WaitForTimeCondition(2);Debug.Log("等待两秒");}IEnumerator TestCoroutine(ICoroutineNode c){yield return new WaitForCoroutineCondition(c);Debug.Log("等待一个协程完成,这里我等待的协程是等待两秒的协程");}
}

全部代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;/// <summary>
/// 一个协程节点的基础结构
/// </summary>
public interface ICoroutineNode
{/// <summary>/// 是否完成/// </summary>bool IsFinished { get; set; }/// <summary>/// 是否暂停/// </summary>bool IsPaused { get; set; }/// <summary>/// 枚举器,代表协程的主体/// </summary>IEnumerator Fiber { get; }/// <summary>/// 协程等待条件/// </summary>ICoroutineWaitCondition WaitCondition { get; }/// <summary>/// 判断协程是否需要等待/// </summary>/// <returns></returns>bool NeedWait();/// <summary>/// 添加一个等待条件/// </summary>/// <param name="condition"></param>void AddWaitCondition(ICoroutineWaitCondition condition);// 暂停协程void Pause();// 恢复协程void Resume();
}
/// <summary>
/// 一个协程调度器的基础结构
/// </summary>
public interface ICoroutineScheduler
{/// <summary>/// 剩余协程数量/// </summary>int CoroutineCount { get; }/// <summary>/// 向调度器中添加协程/// </summary>/// <param name="fiber">枚举器</param>/// <returns></returns>ICoroutineNode AddCoroutine(IEnumerator fiber);/// <summary>/// 暂停一个协程/// </summary>/// <param name="coroutine"></param>void PauseCoroutine(ICoroutineNode coroutine);/// <summary>/// 恢复一个协程/// </summary>/// <param name="coroutine"></param>void ResumeCoroutine(ICoroutineNode coroutine);/// <summary>/// 移除一个协程/// </summary>/// <param name="coroutine"></param>/// <returns></returns>ICoroutineNode RemoveCoroutine(ICoroutineNode coroutine);/// <summary>/// 移除全部协程/// </summary>void RemoveAllCoroutines();// 更新协程状态,在每帧调用void UpdateCoroutines();
}// 定义等待条件的结构,实现该接口自定义可 yield return的对象
public interface ICoroutineWaitCondition
{/// <summary>/// 判断是否需要继续等待(true则条件未满足继续等待)/// </summary>bool keepWaiting { get; }/// <summary>/// 被暂停时会调用一次/// </summary>void Pause();/// <summary>/// 被恢复时会调用一次/// </summary>void Resume();
}/// <summary>
/// 具体的协程节点实现
/// </summary>
public class CoroutineNode : ICoroutineNode
{// 协程主体(Fiber)public IEnumerator Fiber { get; private set; }// 是否完成public bool IsFinished { get; set; }// 是否暂停public bool IsPaused { get; set; }// 当前节点的等待条件private ICoroutineWaitCondition waitCondition = null;public ICoroutineWaitCondition WaitCondition => waitCondition;// 构造函数,传入一个协程(Fiber)public CoroutineNode(IEnumerator fiber){Fiber = fiber;IsFinished = false;IsPaused = false;}// 添加等待条件public void AddWaitCondition(ICoroutineWaitCondition condition) => waitCondition = condition;// 检查是否需要等待,决定协程是否可以继续执行public bool NeedWait() => waitCondition.keepWaiting;// 暂停等待条件public void Pause() => waitCondition.Pause();// 恢复等待条件   public void Resume() => waitCondition.Resume();
}/// <summary>
/// 协程调度器,管理协程的生命周期和调度
/// 该调度器的协程有执行顺序,前一个协程彻底执行完,下一个协程才开始执行
/// </summary>
public class CoroutineSchedulerOrder : ICoroutineScheduler
{// 用于存储所有协程的队列private Queue<ICoroutineNode> coroutineQueue = new Queue<ICoroutineNode>();//被暂停协程private ICoroutineNode frozenCoroutineNodeOrder = null;//所剩协程数量public int CoroutineCount { get => coroutineQueue.Count; }// 向调度器中追加协程public ICoroutineNode AddCoroutine(IEnumerator fiber){if (fiber == null){return null;}ICoroutineNode coroutine = new CoroutineNode(fiber); // 创建协程节点coroutineQueue.Enqueue(coroutine); // 将节点加入队列return coroutine;}// 停止一个特定的协程,这将阻塞后续的协程public void PauseCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = true;}//恢复一个被暂停的协程public void ResumeCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = false;}// 移除一个协程,视为该协程完成了public ICoroutineNode RemoveCoroutine(ICoroutineNode coroutine){coroutine.IsFinished = true;if (frozenCoroutineNodeOrder == coroutine){frozenCoroutineNodeOrder = null;}var coroutineList = coroutineQueue.ToList();coroutineList.Remove(coroutine);coroutineQueue = new Queue<ICoroutineNode>(coroutineList);return coroutine;}// 移除所有协程,视为已完成public void RemoveAllCoroutines(){foreach (var c in coroutineQueue) c.IsFinished = true;frozenCoroutineNodeOrder = null;coroutineQueue.Clear();}// 更新协程状态,在每帧调用public void UpdateCoroutines(){int queueSize = coroutineQueue.Count;if (queueSize == 0) return;ICoroutineNode coroutine = coroutineQueue.Peek(); // 获取队首协程// 如果协程已完成,从队列中移除if (coroutine.IsFinished){coroutineQueue.Dequeue();return;}// 如果协程暂停,执行暂停操作,并跳过本帧处理if (coroutine.IsPaused){if (frozenCoroutineNodeOrder != null && frozenCoroutineNodeOrder == coroutine) return;if (coroutine.WaitCondition != null){coroutine.Pause();frozenCoroutineNodeOrder = coroutine; // 记录冻结的协程                }return;}else if (frozenCoroutineNodeOrder != null && frozenCoroutineNodeOrder == coroutine){coroutine.Resume(); // 如果之前被冻结,现在恢复协程frozenCoroutineNodeOrder = null;}if (coroutine.WaitCondition == null){//什么也不用做,走到MoveNextCoroutine进行初始化}else if (coroutine.NeedWait()) return; // 检查协程是否满足继续执行的条件MoveNextCoroutine(coroutine);}private void MoveNextCoroutine(ICoroutineNode coroutine){// 如果协程可以继续执行,调用 MoveNext() 继续执行协程if (coroutine.Fiber.MoveNext()){System.Object yieldCommand = coroutine.Fiber.Current; // 获取当前协程的返回值var coroutineWaitCondition = yieldCommand as ICoroutineWaitCondition;// 如果返回的是等待条件,添加等待条件到协程节点if (coroutineWaitCondition != null)coroutine.AddWaitCondition(coroutineWaitCondition);elsethrow new System.Exception("yield return type error");}else{coroutine.IsFinished = true; // 标记协程已完成coroutineQueue.Dequeue(); // 将完成的协程移出队列}}
}/// <summary>
/// 每帧会将列表的所有协程执行一遍,不保证顺序
/// </summary>
public class CoroutineScheduler : ICoroutineScheduler
{// 用于存储所有协程的队列private List<ICoroutineNode> coroutineList = new List<ICoroutineNode>();//被暂停的协程private HashSet<ICoroutineNode> frozenCoroutineHashSet = new HashSet<ICoroutineNode>();private List<ICoroutineNode> finishedCoroutines = new List<ICoroutineNode>();//所剩协程数量public int CoroutineCount { get => coroutineList.Count; }// 向调度器中添加协程public ICoroutineNode AddCoroutine(IEnumerator fiber){if (fiber == null){return null;}ICoroutineNode coroutine = new CoroutineNode(fiber); // 创建协程节点coroutineList.Add(coroutine); // 将节点加入队列return coroutine;}// 停止一个特定的协程,不影响其他协程public void PauseCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = true;}//恢复一个协程public void ResumeCoroutine(ICoroutineNode coroutine){coroutine.IsPaused = false;}/// <summary>/// 移除一个协程,视为该协程完成了/// </summary>/// <param name="coroutine"></param>/// <returns></returns>public ICoroutineNode RemoveCoroutine(ICoroutineNode coroutine){coroutine.IsFinished = true;if (frozenCoroutineHashSet.Contains(coroutine)) frozenCoroutineHashSet.Remove(coroutine);return coroutine;}// 移除所有协程,视为已完成public void RemoveAllCoroutines(){foreach (var c in coroutineList) c.IsFinished = true;frozenCoroutineHashSet.Clear();}// 更新协程状态,在每帧调用public void UpdateCoroutines(){int queueSize = coroutineList.Count;if (queueSize == 0) return;foreach (var coroutine in coroutineList){//已完成协程移除列表if (coroutine.IsFinished){finishedCoroutines.Add(coroutine);continue;}//被暂停协程if (coroutine.IsPaused){if (frozenCoroutineHashSet.Contains(coroutine)) continue;if (coroutine.WaitCondition != null){coroutine.Pause();frozenCoroutineHashSet.Add(coroutine);}continue;}else if (frozenCoroutineHashSet.Contains(coroutine))//是否是被暂停过的协程要恢复{coroutine.Resume();frozenCoroutineHashSet.Remove(coroutine);}if (coroutine.WaitCondition == null){}else if (coroutine.NeedWait()) continue;MoveNextCoroutine(coroutine);}// 移除已经完成的协程foreach (var finished in finishedCoroutines){coroutineList.Remove(finished);}finishedCoroutines.Clear();}private void MoveNextCoroutine(ICoroutineNode coroutine){// 如果协程可以继续执行,调用 MoveNext() 继续执行协程if (coroutine.Fiber.MoveNext()){System.Object yieldCommand = coroutine.Fiber.Current; // 获取当前协程的返回值var coroutineWaitCondition = yieldCommand as ICoroutineWaitCondition;// 如果返回的是等待条件,添加等待条件到协程节点if (coroutineWaitCondition != null)coroutine.AddWaitCondition(coroutineWaitCondition);elsethrow new System.Exception("yield return type error");}else{coroutine.IsFinished = true; // 标记协程已完成finishedCoroutines.Add(coroutine);}}
}#region 等待条件
// 等待帧
public struct WaitForFrameCondition : ICoroutineWaitCondition
{private int waitFrame; // 等待帧数bool ICoroutineWaitCondition.keepWaiting{get{waitFrame--;return waitFrame > 0;}}public WaitForFrameCondition(int frame){if (frame <= 0){throw new ArgumentException("Frame must be greater than 0.", nameof(frame));}waitFrame = frame;}// 无需实现void ICoroutineWaitCondition.Pause() { }// 无需实现void ICoroutineWaitCondition.Resume() { }
}// 等待时间
public struct WaitForTimeCondition : ICoroutineWaitCondition
{bool ICoroutineWaitCondition.keepWaiting{get{waitTime -= Time.deltaTime;return waitTime > 0;}}private float waitTime; // 等待时间public WaitForTimeCondition(float time){waitTime = time;}// 无需实现void ICoroutineWaitCondition.Pause() { }// 无需实现void ICoroutineWaitCondition.Resume() { }}// 等待其他协程完成的条件类
public struct WaitForCoroutineCondition : ICoroutineWaitCondition
{bool ICoroutineWaitCondition.keepWaiting{get{return !coroutine.IsFinished;}}private ICoroutineNode coroutine; // 被依赖的协程节点public WaitForCoroutineCondition(ICoroutineNode coroutine){this.coroutine = coroutine;}// 暂停依赖的协程void ICoroutineWaitCondition.Pause() => this.coroutine.Pause();// 恢复依赖的协程void ICoroutineWaitCondition.Resume() => this.coroutine.Resume();
}#endregion


http://www.mrgr.cn/news/31126.html

相关文章:

  • 文件上传js代码
  • Virtuoso服务在centos中自动停止的原因分析及解决方案
  • 【云安全】云服务安全攻防
  • U 盘显示需要格式化才能用?一针见血的修复方法在这里!速看!
  • 量子噪声流加密(二:如何隐匿通信密文)
  • 蓝队技能-应急响应篇Web内存马查杀JVM分析Class提取诊断反编译日志定性
  • Centos 7 搭建Samba
  • YOLOv5白皮书-第Y1周:调用官方权重进行检测
  • Spring MVC 启动与请求处理流程解析
  • 环保行动中的关键力量:油烟净化器如何发挥重要作用
  • 乐观锁、悲观锁及死锁
  • 抖音怎么录屏保存?网页录屏和直播内容录制屏幕工具软件推荐
  • Ubuntu 22.04 源码下载的几种方法
  • 【用Java学习数据结构系列】对象的比较(Priority Queue实现的前提)
  • 鸿蒙手势交互(三:组合手势)
  • 模型案例:| 篮球识别模型
  • Python学习——【3.1】函数
  • 超详细!百分百安装成功pytorch,建议收藏
  • 【Node.js Vue】还在为选什么乐器发愁?乐器推荐系统帮你解决难题,基于用户行为分析的智能推荐,让你不再为音乐器材烦恼
  • 监控易监测对象及指标之:全面监控GBase数据库