我正在尝试使用 C# 创建一个“行为树”。
对于任何不知道的人来说,行为树基本上是一个框架,你可以围绕它构建一个 AI。有序列器、选择器、装饰器、复合动作和其他东西。
我找到了一个在 C# 中实现了“行为树”的库,位于此处(http://code.google.com/p/treesharp/),但我无法理解如何实际使用它,因为没有示例代码我可以借鉴。这里的任何人都可以制作一些简单的示例代码来展示如何实际使用这个框架..或者您可能知道在 C# 中实现行为树的另一种方法?
非常感谢!
我正在尝试使用 C# 创建一个“行为树”。
对于任何不知道的人来说,行为树基本上是一个框架,你可以围绕它构建一个 AI。有序列器、选择器、装饰器、复合动作和其他东西。
我找到了一个在 C# 中实现了“行为树”的库,位于此处(http://code.google.com/p/treesharp/),但我无法理解如何实际使用它,因为没有示例代码我可以借鉴。这里的任何人都可以制作一些简单的示例代码来展示如何实际使用这个框架..或者您可能知道在 C# 中实现行为树的另一种方法?
非常感谢!
我刚刚查看了那个实现,我发现自己想知道为什么相对简单的事情需要这么多代码。
从你所说的来看,你想要一种简单的方式来组成行为。我认为这里的行为是代理从状态到零个或多个动作的映射。您可以使用 C# lambda 轻松对此进行建模。例如:
Action Selector(Func<bool> cond, Action ifTrue, Action ifFalse) {
return () => { if cond() then ifTrue() else ifFalse() };
}
Action Sequencer(Action a, Action b) {
return () => { a(); b(); }
}
树的叶子是简单的动作,可以做一些适合状态的事情。您只需执行它即可“运行”一棵树。
如果您想花哨,可以参数化此方案以使状态显式。
希望这可以帮助。
---- 附录 ----
Jason 询问了如何使用这种方法的示例,所以这里有一个简单的“AI”巡逻警卫示例(我假设 WorldState 对应于评估行为树时的环境描述):
Func<bool> ifPlayerIsInSight = () => ...true iff WorldState shows guard can see player...;
Action shootAtPlayer = () => { ...aim guard's weapon at player and fire... };
Func<bool> ifUnderFire = () => ...true iff WorldState shows guard hears player gunfire...;
Action takeCover = () => { ...guard runs for nearest shelter... };
Action walkBackAndForthGuardingDoorway = () => { ...default guard patrol behaviour... };
Action patrollingGuardBehaviour =
Selector(ifPlayerIsInSight, shootAtPlayer,
Selector(ifUnderFire, takeCover,
walkBackAndForthGuardingDoorway));
要让守卫做点什么,只需调用patrollingGuardBehaviour()
. 请注意,各种子操作和测试可以作为具有正确签名的方法实现,而不是作为 lambda 内联。您可以将其他组合器添加到Selector
and Sequencer
,例如,用于并行活动。
看起来 TreeSharp 背后的开发者之一 apocdev有一些将 TreeSharp 用于某种施法魔兽世界播放器的代码。
这是一个片段:
public Composite CreateSpellCheckAndCast(string name)
{
return new Decorator(
ret => Spells.CanCast(name),
new Action(ret => Spells.Cast(name)));
}
我不确定,但这里的用法似乎很简单:Decorator
该类看起来像是Spells.CanCast
在尝试执行某些操作()之前检查谓词( Spells.Cast
)。
所以 aComposite
可能是一个Action
可以做几件事的 a,例如预先检查一个谓词或按顺序执行几个动作。
apocdev 的博客提到了行为树的概述,它链接到对序列、选择器和装饰器的更一般的描述。
C# lambda 在涉及闭包时会变得昂贵,因为这将导致在您的 BT 的每一帧/迭代中进行分配。您可以使用黑板避免关闭,但有一种更简单的方法。
您可以使用短路条件运算符&&
和||
. 这种方法在这里说明:
https ://github.com/eelstork
那么巡逻示例将如下所示:
Status Patrol()
=> (playerInSight && Shoot(player))
|| (underFire && TakeCover())
|| GuardDoorway();