私はビヘイビアツリーを回避しようとしています。そのため、いくつかのテストコードを作成しています。私が苦労していることの1つは、優先度の高いものが発生したときに現在実行中のノードをプリエンプトする方法です。
兵士の次の単純な架空の行動ツリーを考えてみましょう。
いくつかのティックが過ぎ、近くに敵がいなかったと仮定します。兵士は草の上に立っていたため、実行するためにSit downノードが選択されます。
再生するアニメーションがあるため、Sit downアクションの実行に時間がかかりRunning
、ステータスとして戻ります。ティックが1つまたは2つ経つと、アニメーションはまだ実行されていますが、敵は近くにいますか?条件ノードのトリガー。次に、攻撃ノードを実行できるように、できるだけ早くシットダウンノードをプリエンプトする必要があります。理想的には、兵士は座っても終わらない-座ったばかりの場合は、代わりにアニメーションの方向を逆にするかもしれません。現実性を高めるために、もし彼がアニメーションの転換点を過ぎた場合、代わりに座ってから立ち直るようにするか、恐らく脅威に反応するために急いでつまずかせることを選択するかもしれません。
このような状況に対処する方法についてのガイダンスを見つけることができませんでした。過去数日間に私が消費したすべての文献とビデオ(そして、それはたくさんありました)は、この問題を回避するようです。私が見つけた最も近いものは、実行中のノードをリセットするというこの概念でしたが、シットのようなノードは「ちょっと、まだ終わっていない!」と言う機会を与えません。
おそらく、基本クラスでPreempt()
or Interrupt()
メソッドを定義することを考えましたNode
。さまざまなノードが適切に処理することができますが、この場合は、できるだけ早く兵士を元に戻してから戻りSuccess
ます。このアプローチではNode
、他のアクションとは別に条件の概念を自分のベースに持たせる必要があると思います。この方法では、エンジンは条件のみをチェックでき、条件が満たされた場合、アクションの実行を開始する前に現在実行中のノードをプリエンプトします。この差別化が確立されていない場合、エンジンは無差別にノードを実行する必要があるため、実行中のアクションをプリエンプトする前に新しいアクションをトリガーできます。
参考のために、現在の基本クラスを以下に示します。繰り返しますが、これはスパイクなので、できる限りシンプルに保ち、必要なときに、そして理解したときにのみ複雑さを加えようとしました。
public enum ExecuteResult
{
// node needs more time to run on next tick
Running,
// node completed successfully
Succeeded,
// node failed to complete
Failed
}
public abstract class Node<TAgent>
{
public abstract ExecuteResult Execute(TimeSpan elapsed, TAgent agent, Blackboard blackboard);
}
public abstract class DecoratorNode<TAgent> : Node<TAgent>
{
private readonly Node<TAgent> child;
protected DecoratorNode(Node<TAgent> child)
{
this.child = child;
}
protected Node<TAgent> Child
{
get { return this.child; }
}
}
public abstract class CompositeNode<TAgent> : Node<TAgent>
{
private readonly Node<TAgent>[] children;
protected CompositeNode(IEnumerable<Node<TAgent>> children)
{
this.children = children.ToArray();
}
protected Node<TAgent>[] Children
{
get { return this.children; }
}
}
public abstract class ConditionNode<TAgent> : Node<TAgent>
{
private readonly bool invert;
protected ConditionNode()
: this(false)
{
}
protected ConditionNode(bool invert)
{
this.invert = invert;
}
public sealed override ExecuteResult Execute(TimeSpan elapsed, TAgent agent, Blackboard blackboard)
{
var result = this.CheckCondition(agent, blackboard);
if (this.invert)
{
result = !result;
}
return result ? ExecuteResult.Succeeded : ExecuteResult.Failed;
}
protected abstract bool CheckCondition(TAgent agent, Blackboard blackboard);
}
public abstract class ActionNode<TAgent> : Node<TAgent>
{
}
誰かが私を正しい方向に導くことができる洞察を持っていますか?私の考えは正しい線に沿っていますか、それとも私が恐れるほど素朴ですか?
Stop()
アクティブノードを終了する前にコールバックを呼び出す)