我正试图统一实现行为树,现在我正在为每个节点/复合/动作使用Tick()函数
我想做的是按顺序进行的,例如:
在节点列表中开始for循环迭代
在当前节点上启动刻度功能
等待直到节点滴答声返回失败/成功
转到下一个节点,然后继续执行步骤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();
}
}
答案 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();
}