在 C# 中创建 AI 行为树 - 如何?

发布于 2024-10-03 07:36:10 字数 336 浏览 10 评论 0原文

我正在尝试使用 C# 创建“行为树”。

对于任何不知道的人来说,行为树基本上是一个可以围绕它构建人工智能的框架。有序列器、选择器、装饰器、复合动作和其他东西。

我找到了一个在 C# 中实现“行为树”的库,位于此处 (http:// code.google.com/p/treesharp/),但我无法理解如何实际使用它,因为没有可以借鉴的示例代码。这里有人可能会制作一些简单的示例代码来展示如何实际使用这个框架..或者也许您知道在 C# 中实现行为树的另一种方法?

非常感谢!

I am attempting to create a "behavior tree" using C#.

For anyone who doesn't know, a behavior tree is basically a framework that you can construct an AI around. There are Sequencers, Selectors, Decorators, composite actions, and other things.

I have found a single library that has implimented a "behavior tree" in C#, located here (http://code.google.com/p/treesharp/) but I cannot understand how to actually use it since there is no example code I can draw from. Could anyone here perhaps make some simple example code that shows how to actually use this framework.. or perhaps you know of another way to impliment a behavior tree in C#?

Thanks so much!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蘸点软妹酱 2024-10-10 07:36:10

我刚刚查看了该实现,我发现自己想知道为什么相对简单的东西需要这么多代码。

从你所说的来看,你想要一种简单的方式来组成行为。我认为这里的行为是代理从状态到零个或多个动作的映射。您可以使用 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 内联。您可以向SelectorSequencer 添加其他组合器,例如用于并行活动。

I just looked at that implementation and I find myself wondering why so much code is needed for something relatively simple.

From what you say, you want a simple way of composing behaviours. A behaviour here, I presume, is a mapping from a state to zero or more actions by an agent. You can model this very easily using C# lambdas. For example:

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(); }
}

The leaves of your tree are simple Actions that do something appropriate to the state. You "run" a tree simply by executing it.

If you want to get fancy, you can parameterise this scheme to make the state explicit.

Hope this helps.

---- Addendum ----

Jason asked for an example of how you could use this approach, so here's a simple "AI" patrolling guard example (I assume WorldState corresponds to a description of the environment at the time the behaviour tree is evaluated):

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));

To make the guard do something, just call patrollingGuardBehaviour(). Note that the various subactions and tests can be implemented as methods with the right signatures rather than inline as lambdas. You can add other combinators to Selector and Sequencer, e.g., for parallel activity.

ゝ偶尔ゞ 2024-10-10 07:36:10

看起来 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)。

因此,Composite 可能是一个可以执行多项操作的 Action,例如,预先检查谓词或按顺序执行多个操作。

apocdev 的博客 提到 < a href="http://aigamedev.com/open/articles/bt-overview/" rel="nofollow">行为树概述,链接到 序列选择器装饰器

It looks like one of the devs behind TreeSharp, apocdev, has some code that uses TreeSharp for some kind of spell-casting World of Warcraft player.

Here's a snippit:

public Composite CreateSpellCheckAndCast(string name)
{
    return new Decorator(
        ret => Spells.CanCast(name),
        new Action(ret => Spells.Cast(name)));
}

I'm not certain, but the usage here seems pretty simple: the Decorator class looks like it checks a predicate (Spells.CanCast) before trying to execute some action (Spells.Cast).

So a Composite is perhaps an Action that can do several things, e.g. check a predicate beforehand or execute several actions in sequence.

apocdev's blog mentions this overview of behavior trees, which links to more general descriptions of sequences, selectors, and decorators.

七颜 2024-10-10 07:36:10

当 C# lambda 涉及闭包时,它们会变得昂贵,因为这将导致 BT 的每个帧/迭代都进行分配。
您可以使用黑板来避免关闭,但还有一种更简单的方法。

您可以使用短路条件运算符 &&|| 来实现行为树。
这种方法如下所示:
https://github.com/eelstork

那么巡逻示例将如下所示:

Status Patrol()
    => (playerInSight && Shoot(player)) 
    || (underFire && TakeCover())
    || GuardDoorway();

C# lambdas get expensive when they involve closures as this will cause allocations at every frame/iteration of your BT.
You can avoid closures using a blackboard, but there is an easier approach.

You can implement behavior trees using the short-circuiting conditional operators && and ||.
This approach is illustrated here:
https://github.com/eelstork

Then the patrol example would look like:

Status Patrol()
    => (playerInSight && Shoot(player)) 
    || (underFire && TakeCover())
    || GuardDoorway();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文