Design and usage of Behavior Trees

Hello.
I am setting up a framework for AI. Goal oriented planning goes in Blueprints. And low level compact reusable tasks are in Behavior Trees. To achieve that I need to dynamically switch between Behavior Trees.
After spending a good amount of time on research, it seems that Blueprint implementation for Behavior Trees doesn’t allow me to structure the system properly.

  • There is no way to swap full Behavior Trees. Unreal assumes there’s one BT for one AIController or BehaviorTreeComponent. But there’s Dynamic BT nodes!
  • Dynamic BT nodes can only be assigned with SetDynamicSubtree function of BehaviorTreeComponent, there’s no way to use a variable from Blackboard
  • Unfortunately, BehaviorTreeComponent does not have any way to extract its Blackboard. Which is required to control the execution of BT from Blueprint (Abort it gracefully).
  • There is BlackboardComponent, the purpose of which is rather mysterious. Is there any way to make them friends with BehaviorTreeComponent?
  • Having a BehaviorTreeComponent on an AIController is itself a questionable move, because AIController can play BTrees without additional components through RunBehaviorTree node. Why there’s 2 entities that both can play BTs?
  • Additionally, AIController has a useful local Blackboard variable, which is assigned with BT’s blackboard when it starts to play
  • There is one huge downside of AIController though: RunBehaviorTree is the only public function of AIController regarding BTs, so there’s no way to control the execution or use dynamic BTs
    Vicious circle.

I am either missing some key knowledge, or the Blueprint implementation is indeed rather limited, scattered and unfinished?
I would very much appreciate a developer with a deeper understanding to guide me and shed some light on how to implement this.

A bonus question: is it easier to work with BTs using C++?

After some further investigations and trial-and-error approach I managed to set up the system. I’ll drop the answer here to hopefully help some roaming developer in the future.

  • First of all, having BehaviorTreeComponent means that AIController would use it to run BTrees after a call to RunBehaviorTree. Not mentioned anywhere, not sure if it’s “intuitive”, but that’s how it goes. This can be checked with IsRunning function of the component before and after that call.
  • Now we know where BT is running, so we can utilize BehaviorTreeComponent’s SetDynamicSubTree functionality. Alas, this is not straightforward. The function would fail if the tree is not running. So normally, to avoid BT knocking into an empty Run Behavior Dynamic node, it should be guarded by a Blackboard Decorator.
  • Next issue one might encounter is that BT still thinks that the Run Behavior Dynamic node is empty with no particular reason. That’s where one should check Blackboards assigned to parent BT and the dynamically inserted one. Those must be the same. I tried to use parent and child Blackboard but to no avail.
  • One subtle detail is that AIController has a hidden Blackboard component on it. Try to add your own, and Unreal won’t let you name it “Blackboard”, and suggest “Blackboard1”. This is not a huge issue so far, as this component is available inside Blueprint by getting Blackboard variable node. This component corresponds to the blackboard of the running BT.

Overall, it seems feasible to dynamically substitute Behavior Trees on the fly, but the road there is weirdly twisted. I wonder how difficult it is to make a proper Init, Shutdown, Interrupt functionality for the subtrees.