unity3d 启动、暂停、恢复和停止Unity协同程序?,

whlutmcx  于 2023-01-26  发布在  其他
关注(0)|答案(1)|浏览(331)

我有一个类Program,它是一个Nodes列表,包含一个方法IEnumerator Invoke()Program类遍历每个调用它的Node。我希望能够提供启动、暂停、恢复和停止执行的方法。启动将导致调用从列表的顶部开始,暂停将有效地“停止”执行,并允许Resume能够在调用Pause时拾取执行所在的位置,而Stop将停止所有函数,并需要调用Start才能重新开始。使用Unity的内置协程,这甚至是可能的,如果是,我如何暂停/恢复一个协同程序?
编辑
我所寻找的是如何从本质上暂停Program的示例,并能够在同一步骤中恢复它。
如果我正确地理解了其中一条评论,它提出的建议会是类似于这个的东西吗?

public abstract class Node {
 public abstract IEnumerator Invoke(ProgramCaller caller);
}

public class Program : Node {
 private List<Node> nodes;

 public override IEnumerator Invoke(ProgramCaller caller) {
  int index = 0;

  while(index < nodes.Count) {
   if(caller.Paused) {
    yield return null;
   }
   else {
    yield return nodes[index].Invoke(caller);
    index++;
   }
  }
 }
}
euoag5mw

euoag5mw1#

所以从我读到的是你有。

public class Node
{
    public IEnumerator Invoke()
    {
        yield return null;
    }
}

那么Unity协程基本上是使用IEnumerator并在特定时间间隔调用MoveNext(默认为Update,除非使用特殊的WaitForFixedUpdate等)。
所以你可以简单地让Program实现它,比如。

public class Program : IEnumerator
{
    public Node[] nodes;

    private int index = -1;
    private IEnumerator currentNode;

    public bool MoveNext()
    {
        if (nodes == null || nodes.Length == 0)
        {
            return false;
        }

        while (currentNode == null)
        {
            if (index >= nodes.Length)
            {
                return false;
            }

            index++;
            currentNode = nodes[index]?.Invoke();
        }

        if (currentNode.MoveNext())
        {
            return true;
        }

        currentNode = null;
        return true;
    }

    public void Reset()
    {
        index = -1;
        currentNode = null;
    }

    public object Current => null;
}

然后你可以把它链接到一个协程,从一个MonoBehaviour,像这样。

public class Example : MonoBehaviour
{
    public Program program;
    private Coroutine currentRoutine;

    // just a name alias
    public void StartProgram() => RestartProgram();
    
    public void RestartProgram()
    {
        StopProgram();
        
        ResumeProgram();
    }

    public void ResumeProgram()
    {
        currentRoutine = StartCoroutine(program);
    }

    public void PauseProgram()
    {
        if (currentRoutine != null)
        {
            StopCoroutine(currentRoutine);
        }
    }

    public void StopProgram()
    {
        PauseProgram();

        program.Reset();
    }
}

正如您所看到的,Start/Stop和Pause/Resume之间的唯一区别是重置或不重置Program
或者,也许更简单:当根据MonoBehaviour禁用协程时,协程自动暂停,当再次启用时,协程恢复。
=〉如果您可以选择为每个程序设置一个专用的runner组件,那么您真正需要的就是重置部分,您可以简单地执行以下操作

public class Program
{
    public Node[] nodes;

    public IEnumerator Run()
    {
        foreach (var node in nodes)
        {
            yield return node.Invoke();
        }
    }
}

这样,您可以将它们全部作为一个IEnumerator运行,然后

public class Example : MonoBehaviour
{
    public Program program;
    private Coroutine currentRoutine;

    // just a name alias
    public void StartProgram() => RestartProgram();
    
    public void RestartProgram()
    {
        StopProgram();
        
        currentRoutine = StartCoroutine(program.Run());
    }

    public void ResumeProgram()
    {
        enabled = true;
    }

    public void PauseProgram()
    {
        enabled = false;
    }

    public void StopProgram()
    {
        if (currentRoutine != null)
        {
            StopCoroutine(currentRoutine);
        }
    }
}

相关问题