Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an AI Behavior Tree in C# - How?

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!

like image 664
Jason Avatar asked Nov 22 '10 02:11

Jason


3 Answers

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.

like image 189
Rafe Avatar answered Oct 18 '22 11:10

Rafe


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.

like image 31
Nate Kohl Avatar answered Oct 18 '22 10:10

Nate Kohl


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();
like image 42
Tea Avatar answered Oct 18 '22 10:10

Tea