Selecting external tree

caleidon

Member
I am trying to achieve functionality where an agent can move, eat, chop wood, mine, farm and do all sorts of different jobs which can change at anytime on runtime based on some priorities. (he can only do one type of job at a time)

I have found this forum post which was super useful because it's basically asking the same thing, however I have a couple more questions.

1. Why should we go with the method that was described in the post? Is this just a common practice of how to do this sort of thing or is there any specific benefit as opposed to loading in all possible Job types and then switching between them without reloading the tree, based on some conditional evaluation?

2. If we DO go with the said method, since the tree needs to re-load every time a new job type is selected, how do we actually re-load it? What specific code can be used to achieve this?

3. Finally, since we are often going to be re-loading this main tree to switch out it's external behavior trees based on the job type, how expensive is this reloading process and would it make sense to use external behavior tree pooling here?

Thank you!
 
1. Why should we go with the method that was described in the post? Is this just a common practice of how to do this sort of thing or is there any specific benefit as opposed to loading in all possible Job types and then switching between them without reloading the tree, based on some conditional evaluation?
That is the built in approach to handling this situation.

2. If we DO go with the said method, since the tree needs to re-load every time a new job type is selected, how do we actually re-load it? What specific code can be used to achieve this?
You should save your tree out to an external tree with the Behavior Tree Reference tasks contained within it and then assign the ExternalTree to the BehaviorTree component. When the tree is enabled with EnableBehavior it will load the subtrees. You can then reset the tree by reassigning the ExternalTree property.

3. Finally, since we are often going to be re-loading this main tree to switch out it's external behavior trees based on the job type, how expensive is this reloading process and would it make sense to use external behavior tree pooling here?
You should definitely pool the trees, but you'll want to profile it for your project as it highly depends on the tasks that you include. If this approach is cost prohibitive on load you could load all of the external trees at once and then create a new composite task which selects the subbranch, similar to how your Behavior Tree Reference task selected a different subtree.
 
That is the built in approach to handling this situation.


You should save your tree out to an external tree with the Behavior Tree Reference tasks contained within it and then assign the ExternalTree to the BehaviorTree component. When the tree is enabled with EnableBehavior it will load the subtrees. You can then reset the tree by reassigning the ExternalTree property.


You should definitely pool the trees, but you'll want to profile it for your project as it highly depends on the tasks that you include. If this approach is cost prohibitive on load you could load all of the external trees at once and then create a new composite task which selects the subbranch, similar to how your Behavior Tree Reference task selected a different subtree.
I'm having some trouble re-loading the tree with a different subtree based on job type. Here's the test code:

C#:
public class ChooseJobTree : BehaviorTreeReference
{
    public List<ExternalBehavior[]> PossibleJobs;
    public static int jobType = 0;

    public override ExternalBehavior[] GetExternalBehaviors()
    {
        if (jobType == 0)
        {
            Debug.Log($"jobtype is 0 so returning mine");
            return PossibleJobs[0];
        }
        else
        {
            Debug.Log($"jobtype is 1 so returning pickup");

            return PossibleJobs[1];
        }
    }
}


C#:
if (Keyboard.current[Key.T].wasPressedThisFrame)
        {
            if (ChooseJobTree.jobType == 0) { ChooseJobTree.jobType++; }
            else { ChooseJobTree.jobType--; }
            bt.DisableBehavior();
            bt.ExternalBehavior = externalBehavior;
            bt.EnableBehavior();
        }

In the PossibleJobs List there are 2 subtrees that I want to switch out. If I change the jobType to 1, save, restart the game, the main tree indeed loads a different subtree, however I cannot get this to work at runtime.

When the 'T' key is pressed, I'm doing as you said. Changing the jobType of the BehaviorTreeReference so that when GetExternalBehaviors is called it loads a different external tree. Then, I'm disabling the main tree, changing the external behavior, and re-enabling it again. The tree successfully reloads, however, the same task is loaded.
 
I changed

C#:
bt.DisableBehavior();
bt.ExternalBehavior = externalBehavior;
bt.EnableBehavior();

to

C#:
bt.DisableBehavior();
bt.ExternalBehavior = null;
bt.ExternalBehavior = externalBehavior;
bt.EnableBehavior();

and now this works. I guess this is the correct way to reassign a tree?
 
Last edited:
Top