【问题标题】:Control group of coroutines协程控制组
【发布时间】:2020-03-23 11:15:13
【问题描述】:

我想在一个组中收集一些协程,以便 group.stop() 停止所有协程。有办法吗?

如果我要手动执行,我会使用一组协程,并且我会包装我的所有协程,以便它们在自然完成时从集合中删除。但这种包装听起来像是对性能的打击。

理想情况下,我想定义一个包含我的协程的子反应器 (MonoBehaviour),然后将子反应器视为协程,允许从主反应器启动和停止它。

谢谢!

【问题讨论】:

  • 将它们存储在列表或字典中怎么样?
  • 完成后如何从这个容器中自动弹出它们?我的协程在几秒/分钟后停止,但我继续创建新的。

标签: c# unity3d coroutine


【解决方案1】:

例如,您可以将它们存储在字典中,例如

private Dictionary<int,Dictionary<int,Coroutine>> routines = new Dictionary<int, Dictionary<int,Coroutine>>();

所以外层字典是一组例程,内层字典将每个协程链接到该组中唯一的routineIndex。

所以当你开始一个例程时,你传入IEnumerator 和你想要开始它的组索引。

然后例程本身嵌套在一个通用工作例程中执行,该例程通过 groupIndex 和例程索引从routines 字典中自动删除相应的例程:

public void StartRoutine(int groupIndex, IEnumerator routine)
{
    if (!routines.ContainsKey(groupIndex))
    {
        routines.Add(groupIndex, new Dictionary<int, Coroutine>());
    }

    // Get next available index within group
    var routineIndex = 0;
    while (routines[groupIndex].ContainsKey(index))
    {
        routineIndex++;
    }

    routines[groupIndex].Add(routineIndex, StartCoroutine(Worker(routineIndex, index,  routine)));
}

// pass in the group and routine index
// so each worker "instance" knows exactly
// which entry to remove from the routines
// Dictionary when it is done
private IEnumerator Worker(int groupIdx, int routineIdx, IEnumerator routine)
{
    yield return routine;

    // when done remove from dictionary
    routines[groupIdx].Remove(routineIdx);
}

现在您可以通过使用例如组索引停止所有例程

public void Stop(int groupIdx)
{
    if(!routines.ContainsKey(groupIdx)) return;

    foreach (var routine in routines[groupIdx].Values)
    {
        StopCoroutine(routine);
    }

    routines.Remove(groupIdx);
}

为了让事情变得更简单,而不是 groupIndex 的 int,您可以将其替换为 enum,例如

public enum GroupID
{
    GroupA,
    GroupB,
    etc
}

注意:在智能手机上输入并未经测试,但我希望这个想法变得清晰

【讨论】:

  • 非常清楚,非常感谢。如果我必须将例程的每个迭代都包装在 Worker 中,我害怕开销,但我忘记了我可以生成例程本身,所以开销是可以接受的。
  • 我一直不清楚的一件事是,你不应该用 IEnumerator 启动协程然后用协程停止它,但是没有 StartCoroutine 方法就无法实例化协程
  • 这就是为什么我们需要routineIdx,根据对Worker的调用的标识符来匹配要停止的协程。
  • 是的,但是你看你是用这个方法StartCoroutine(IEnumerator)启动它,然后用StopCoroutine(Coroutine)停止它,根据Unity这不是一个好主意,但是没有办法用一个Coroutine对象
猜你喜欢
  • 2017-09-18
  • 2017-08-19
  • 1970-01-01
  • 1970-01-01
  • 2020-05-01
  • 2021-07-22
  • 1970-01-01
  • 2014-02-26
  • 1970-01-01
相关资源
最近更新 更多