If you have the computational resources, it is best to evaluate the tree every frame. If CPU time becomes an issue, you may switch to event-driven BTs or update with lower frequency.
Behavior Switching
To properly handle switch to a different behavior, it is vital, that all your nodes enforce an init-update-done lifecycle. That is, prior to switching to a different behavior in a selector, you call done() on the subtree you are terminating and then init() on the new subtree, only after both finish you start sending updates.
The init/done calls propagate through the tree the same way regular updates do. In the articles on AIGameDev, Alex supposes, that the init/done calls are instantaneous, but
if your game features more complex logic, it might be useful to allow the init and done operations to take more than one frame, that is the node can now have much more states:
- none (prior to initialization)
- initializing (the init operation requires more updates)
- running (init finished, executing normal updates).
- stopping (node is requested to stop but requires more updates)
- done (node has finished)
Note that if a selector is about to change which branch is executing, it first signals the currently running branch to stop and only after the branch transitions to "done" does it start executing the new branch.
This requires more complex logic in the sequences/selectors/decorator nodes but may save you a lot of headache in the long run.
It also lets you to create special nodes that have a whole subtree to perform for when initializing/stopping.
E.g. you have a behavior when your character is drinking in a pub, in the init subtree you perform a sitting animation and notify the barman that you want a beer. In the stopping subtree you perform a standup animation a notify the barman that you are leaving.
Handling distractions
If the tree switches to a different subtree upon a sound distraction only to realize it was not actually a distraction and switches back, you are doing something wrong. The subtree should be switched only when the impulse is actually considered important. A parallel node may help you to run some more complex code to evaluate the impulse without interrupting the guard behavior. If the code in the parallel branch decides the distraction is important, it sends the impulse to the selector to do the actual change (e.g. sets a variable).
If you for some reason need to maintain state when the NPC switches to a different behavior, you may have two kinds of operations to stop execution of a subtree:
Stop - stops the execution and clears state (as usual)
Suspend - stops the execution without clearing the state (e.g. a sequence node remembers the index of currently executed node).
A selector then may decide whether to stop or suspend the tree. Once again, you may need intermediate state "suspending" to let suspend take more than one frame.