Constructing and switching Behavior Trees

nanodeath

New member
Hi,

I'm have a node in my main behavior tree that, when executed, executes this:

var comp = pawn.GetComponent<BehaviorTree>();
comp.DisableBehavior();
comp.ExternalBehavior = externalBehavior;
comp.EnableBehavior();


This externalBehavior object is constructed like this before being shoved into a Queue:

public ExternalBehaviorTree BehaviorTree;
// ...
var tree = Instantiate(BehaviorTree);
tree.Init();
tree.SetVariableValue("location", gameObject);
// add tree to Queue


And this seems to work, but it throws an error:

NullReferenceException: Object reference not set to an instance of an object
BehaviorDesigner.Runtime.BehaviorManager.RunParentTask (BehaviorDesigner.Runtime.BehaviorManager+BehaviorTree behaviorTree, System.Int32 taskIndex, System.Int32& stackIndex, BehaviorDesigner.Runtime.Tasks.TaskStatus status) (at <1cb7df59e12f495fa3a64118298c7b21>:0)
BehaviorDesigner.Runtime.BehaviorManager.RunTask (BehaviorDesigner.Runtime.BehaviorManager+BehaviorTree behaviorTree, System.Int32 taskIndex, System.Int32 stackIndex, BehaviorDesigner.Runtime.Tasks.TaskStatus previousStatus) (at <1cb7df59e12f495fa3a64118298c7b21>:0)
BehaviorDesigner.Runtime.BehaviorManager.RunParentTask (BehaviorDesigner.Runtime.BehaviorManager+BehaviorTree behaviorTree, System.Int32 taskIndex, System.Int32& stackIndex, BehaviorDesigner.Runtime.Tasks.TaskStatus status) (at <1cb7df59e12f495fa3a64118298c7b21>:0)
BehaviorDesigner.Runtime.BehaviorManager.RunTask (BehaviorDesigner.Runtime.BehaviorManager+BehaviorTree behaviorTree, System.Int32 taskIndex, System.Int32 stackIndex, BehaviorDesigner.Runtime.Tasks.TaskStatus previousStatus) (at <1cb7df59e12f495fa3a64118298c7b21>:0)
BehaviorDesigner.Runtime.BehaviorManager.Tick (BehaviorDesigner.Runtime.BehaviorManager+BehaviorTree behaviorTree) (at <1cb7df59e12f495fa3a64118298c7b21>:0)
BehaviorDesigner.Runtime.BehaviorManager.Tick () (at <1cb7df59e12f495fa3a64118298c7b21>:0)
BehaviorDesigner.Runtime.BehaviorManager.Update () (at <1cb7df59e12f495fa3a64118298c7b21>:0)


What am I doing wrong?
 

Justin

Administrator
Staff member
Just to narrow things down, if you directly assign the external behavior tree without instantiating it does it work correctly? When the tree is deserialized it'll take care of any instantiation methods.
 

nanodeath

New member
Well, I need a fresh copy at least, because I need to set variables on it, and I don't want to mutate the "original" behavior tree, in case I need to use it again.

In any case, I updated the code to this:

// var tree = Instantiate(BehaviorTree);
var tree = BehaviorTree;


but it still errors the same way. (Still works, too, fwiw)
 

nanodeath

New member
There may be an entirely different and better way to model what I'm doing, so let me provide more context. Imagine you're using BehaviorDesigner to construct a game like Rimworld or Prison Architect. There's some global queue of "jobs" that needs to be picked up by characters in the game. Like "Build a wall at (10,12)" or "Cook a simple meal". These can be picked up by any character, have variables that have been set, and can even be wired in by mods, so they shouldn't be hardcoded into the main behavior, for example.

The way I'm handling this right now is the main BehaviorTree that the characters are using has a "Take job from global queue" action that sees if the player (or game) has enqueued a new ready-to-go BehaviorTree for the character to use, and if so, straight up replaces the character's current BehaviorTree with that one. Then, when complete, it switches back to its original BehaviorTree.

Is that the right general approach? Or is there something easier that I'm missing? I've thought about placing a "Behavior Tree Reference" object in place of the "Take job from global queue" action and mutating it via game logic, but 1. I didn't think of that originally, and 2. I'm worried about synchronizing behavior across multiple characters, to e.g. prevent multiple characters from taking the "Build a wall at (10, 12)" task. Perhaps I could use a Task Guard or something.
 

Justin

Administrator
Staff member
The approach that you are taking should work. Are you able to reproduce the error in a small repro project? If you can send that project to me via pm or email it would be great.
 
Top