Creating an AI Behavior Tree in C# - How?
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();