Search code examples
artificial-intelligencebehavior-tree

State Like Action In Behavior Tree


From what I understand on Behavior Trees, each Behavior should be a short goal oriented Action that could be done in a few iterations.

So for example, below is an image of a Behavior Tree:

enter image description here

Now let us assume that the Drive To Enemy behavior takes more than a few iterations in the tree. So on each pass Drive To Enemy is called because it is now in the running state.

The problem is I want to call Evade Enemy if an Enemy is nearby. And considering that Drive To Enemy is always called I never get a chance to call Evade Enemy (Should probably be called Avoid Enemy).

  • Should I traverse the Tree EACH pass no matter what Action is currently running?
  • Am I going about this the right way?
  • What is the proper way of handling such a behavior?

Solution

  • I would say traversing all the way back to the top every time would be your last resort if the idea below doesn't work for you:

    As Alex Champandard suggests in his website aigamedev.com, the basic idea instead, is that while you are in the "Drive To Enemy" behaviour, you include some sort of way to run some additional checks to make sure that behaviour should still be continued.

    Alex's method is to use the parallel composite: a type of behaviour tree node that runs all its children simultaneously.

    It would look like this:

    1. MainSelector:
      • Evade Enemy
        • Locate Enemy
        • Drive in oppposite direction
      • Parallel
        • Is Enemy Nearby?
        • Chase Enemy
          • Find path to enemy
          • Drive to enemy
          • Fire Weapon
      • Chase Flag
        • Locate flag
        • Find Path
        • Drive to flag

    The Parallel node will repeatedly keep on evaluating the "Is Enemy Nearby?" node (at a reasonable pace), even when execution is deep within the "Chase Enemy" sub-tree. The moment "Is Enemy Nearby?" returns failure, the parallel will immediately return failure and skip completing the "Chase Enemy" behaviour. Thus, the next evaluation of your tree will reach the "Evade Enemy" behaviour.

    The "Is Enemy Nearby?" condition then, acts as a sort of assertion check or early-out check. Essentially it's like an event-driven feature where your tree can respond to events even while it hasn't completed its iteration yet.

    The way I designed my system though, I don't use parallel behaviours (can't multi-thread properly with the 3rd party game engine I use). I have instead a composite that does pretty much the same thing, only it evaluates the checks in-between each of its children's traversal. Like a sort of interleaved, jumping back-and-forth from normal execution to evaluating the checks. Only if the checks fail do we jump back to the top.