Game AI - Behavior Trees

1.6k Views Asked by At

How do you make a robust AI/scripting system for a game?

1) For all NPC's/environment/entities do you give them a SEPARATE single behavior tree (etc. patrolBehavior, allyBehavior, vendorBehavior, doorBehavior)? If there are 500 units on the screen, should I do a full pass on the tree (going from root -> node/action) or should I do 1-node progress for all the units?

2) I am doing the AI logic in the update() function... but I heard some games have their separate AI thread, any ideas?

3) I'm wondering how to divide my game into sections/chapters... do I use a simple variable (EVENT="Mission 3") to denote how for the player's been, and make it all linear? And then utilize variable in the trees above?

2

There are 2 best solutions below

0
On BEST ANSWER
  1. each NPC/Agent has its own behavior tree. The tree is updated and it 'knows' where to continue, so the efficiency is usually quite good.
  2. AIs can be updated in the main thread, it can also be updated in a separated thead. it depends and up to you.
  3. it depends and up to you.

behaviac is a really excellent one.

behaviac supports the behavior tree, finite state machine and hierarchical task network. Behaviors can be designed and debugged in the designer, exported and executed by the game.

The C++ version is suitable for the client and server side.

and, it is open sourced!

0
On

I'll try to answer your question.

  1. I do all branching logic and behavior trees in a static class for example:
     public static class Behavior
    {
        //Branch
        public static Action Selector(Func<bool> cond, Action ifTrue, Action ifFalse) {
            return () => { if (cond()) { ifTrue(); } else { ifFalse(); } };
            }
        public static Action Sequencer(Action a, Action b) {
              return () => { a(); b(); }
            }

        //Example trees
        public static Func<bool> ifPlayerIsInSight = () => { return true; /*...true iff WorldState shows guard can see player...*/};

        public static Action shootAtPlayer = () => { /*...aim guard's weapon at player and fire...*/ };

        public static Func<bool> ifUnderFire = () => { return true; /*...true iff WorldState shows guard hears player gunfire...*/};

        public static Action takeCover = () => { /*...guard runs for nearest shelter... */};

        public static Action walkBackAndForthGuardingDoorway = () => { /*...default guard patrol behaviour...*/ };

        public static Action patrollingGuardBehaviour =
          Selector(Behavior.ifPlayerIsInSight, Behavior.shootAtPlayer,
            Selector(Behavior.ifUnderFire, Behavior.takeCover,
              Behavior.walkBackAndForthGuardingDoorway));
    }
  1. Do it in LateUpdate() or last so it does not lag the main loop.

  2. It is upto you. You could implement a "State" in each behavior tree or split it out and manage which get used at what time.