使用协程暂停暂停执行功能

时间:2020-03-11 10:25:48

标签: c# unity3d artificial-intelligence

我正试图统一实现行为树,现在我正在为每个节点/复合/动作使用Tick()函数

我想做的是按顺序进行的,例如:

  1. 在节点列表中开始for循环迭代

  2. 在当前节点上启动刻度功能

  3. 等待直到节点滴答声返回失败/成功

  4. 转到下一个节点,然后继续执行步骤1

    我遇到的问题是第3步。我想用协程来实现这一目标。

问题在于断言为true,nodeStat var为None。执行WaitFor Seconds后,控件将返回到Debug.Assert(nodeStat != Status.None);

public class Sequence : Composite
{
    protected override void Start()
    {
        status = Status.Running;
    }
    Status nodeStat = Status.None;
    IEnumerator Recursive(Node nod)
    {
        while (true)
        {
            Debug.Log(nod + "is running");
            Status status = nod.Tick();

            Debug.Log(Time.time + " " + status);
            if (status == Status.Running)
            {
                Debug.Log("start coroutine at : " + Time.time);
                yield return new WaitForSeconds(0.2f);
                Debug.Log("Comtinue coroutine at : " + Time.time);
            }
            else
            {

                Debug.Log("has finished coroutine");
                nodeStat = status;
                break;
            }
        }
    }
    protected override Status Execute()
    {
        foreach(Node nod in ListaNoduri)
        {
            GameManager.Instance.StartCoroutine(Recursive(nod));
            Debug.Assert(nodeStat != Status.None);
            if (nodeStat == Status.Failure)
                return Status.Failure;
        }
        return Status.Success;
    }

    protected override void Exit()
    {
        base.Exit();
    }
    public override Status Tick()
    {
        //Debug.Log(status);
        return base.Tick();
    }
}

2 个答案:

答案 0 :(得分:1)

考虑将IEnumerator Execute() { foreach(Node nod in ListaNoduri) { //wait for the current node to be done before continuing yield return GameManager.Instance.StartCoroutine(Recursive(nod)); Debug.Assert(nodeStat != Status.None); if (nodeStat == Status.Failure){ //do something on failure yield break; } } //do something on success } 用作协程:

fromF("timer://foo-poll?fixedRate=true&delay=5s&period=%d&bridgeErrorHandler=true", pollRate)
    .toF("https4://%s/%s", host, requestPath)
    .log("Received: ${body}")
    .streamCaching("true")
    .unmarshal(new ListJacksonDataFormat(MyObject.class))
    .split()
        .jsonpath("$")
        .log("Split: ${body}")
    .process(barProccessor);

答案 1 :(得分:0)

请记住,Corutine的工作原理类似于线程(异步执行)。

请注意,由于@akaBase指向注释,问题在于您是在调用协程后立即评估nodeStat,而不是在等待协程完成。

因此,您正在分派多个异步调用(每个节点一个),但是您不必等待所有的异步调用。

一种方法可能是在递归中断之前添加事件/委托/动作,在其中存储一个Node的结果,然后对另一个协程(应该是当前的Execute)求值,如果某个委托是错误,结果为错误。

类似的东西:

    private List<bool> nodeExecutionResultsList = new List<bool>();
    private Status statusResult = Status.Failure;
    private Action OnAllNodesEnd = null;

    protected override void Execute()
    {
        OnAllNodesEnd = () => { Debug.Log("Every Node Ends!"); };
        foreach (Node nod in ListaNoduri)
        {
            GameManager.Instance.StartCoroutine(Recursive(nod));            
        }
    }

    IEnumerator Recursive(Node nod)
    {
        while (true)
        {
            Debug.Log(nod + "is running");
            Status status = nod.Tick();

            Debug.Log(Time.time + " " + status);
            if (status == Status.Running)
            {
                Debug.Log("start coroutine at : " + Time.time);
                yield return new WaitForSeconds(0.2f);
                Debug.Log("Comtinue coroutine at : " + Time.time);
            }
            else
            {

                Debug.Log("has finished coroutine");
                nodeStat = status;
                //Do the assert NOW, and register on the list the result
                Debug.Assert(nodeStat != Status.None);
                nodeExecutionResult.Add(nodeStat == Status.Failure);
                break;
            }
        }
    }

    private IEnumerator EvaluateAllNodes()
    {
        while(evaluating)
        {
            //there are the same number of results as nodes
            if(nodeExecutionResultsList.Count == ListaNoduri.Count)
            {
                //check if someone fails
                statusResult = (nodeExecutionResult.Contains(false)) ? Status.Failure : Status.Success;
            }
        }
        OnAllNodesEnd?.Invoke();
    }