开发者

Creating an AI Behavior Tree in C# - How?

开发者 https://www.devze.com 2023-01-26 19:38 出处:网络
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, De

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 ac开发者_Go百科tions, 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!


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.


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.


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

精彩评论

暂无评论...
验证码 换一张
取 消