Duplicate Behavior Tree

How do I duplicate a Behavior Tree and use it in another agent to edit it and have another different Behavior Tree?
I want to duplicate the UCC Integration tree and edit different versions from this.
 
Hi Justin, I would really suggest making a more comprehensive explanation of how to do this, as it is not as intuitive as this answer makes it seem.

I made a new character and gave him a behavior tree where I then set an exported behavior tree to be the external tree. Because some of the varables that come with that tree are gameobject, they are then shown to have a red "!" to the right of them in the behavior tree inspector. Even after setting them to the correct gameobjects on the new chracter they are still shown as red.

I do not know what to do from here and the link above does not really give any guidance as to what to do next. Im simply getting a bunch of error by simply clicking on the new characters body (where he should have the behaviour tree):

error.png

And since I have setup my enemies so that I make a script that refers to variables in the behaviour tree, those variables are absent at Start() so I cant reference them from start and would have to do a bunch of null checking and setting inside update until they are all found.

Why can I not simply tell a new character to have the same behavior tree as another character, and why can a prefab not have a behavior tree? is there some sort of technical reason that hinders this? if I check my prefab body there is just a generic behavior tree, not the one I have in the scene heirarchy. All of this just make its seem a bit counterintuitive and not really in-line with how unity works. Thats fine as long as there is proper documentation to explain how to go about reusing your behavior tree elsewhere. I dont feel that the above linked documentation even comes close to properly explaining it.

to be clear, I am not using small trees here. I like to have all my behaviors in one large tree so I can properly see whats going on at all times.
 
I have now made a a script that holds the references to the necessary gameobjects in order to feed the info to the behaviorTree when it starts up as per your linked documentation. I made a tester Action called EnemyRef which looks like this:

Code:
 public class EnemyRef : Action
    {
        [Tooltip("The object found by name")]
        [RequiredField]
        public SharedGameObject[] storeValues;

        Feeder feeder;

        public override void OnStart()
        {
            feeder = GetComponent<Feeder>();
        }

        public override TaskStatus OnUpdate()
        {
            Debug.Log(storeValues[0].Value + "    " + feeder.this_.name);
            Debug.Log(storeValues[1].Value + "    " + feeder.puppet.name);
            storeValues[0].Value = feeder.this_;
            storeValues[1].Value = feeder.puppet;

            return TaskStatus.Success;
        }

    }

However it doesnt matter what it looks like because that code is never run, the behaviorTree never starts up on my prefabs and therefore the references are not set. I get this error in the log as soon as I run the game:

ArgumentException: The value "null" is not of type "UnityEngine.GameObject" and cannot be used in this generic collection.

Parameter name: value
System.ThrowHelper.ThrowWrongValueTypeArgumentException (System.Object value, System.Type targetType) (at <ab1dc506f380448587ff80868d46ed83>:0)
System.Collections.Generic.List`1[T].System.Collections.IList.Add (System.Object item) (at <ab1dc506f380448587ff80868d46ed83>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeObject (BehaviorDesigner.Runtime.Tasks.Task task, System.Object obj, System.Collections.Generic.Dictionary`2[TKey,TValue] dict, BehaviorDesigner.Runtime.IVariableSource variableSource, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeSharedVariable (System.Collections.Generic.Dictionary`2[TKey,TValue] dict, BehaviorDesigner.Runtime.IVariableSource variableSource, System.Boolean fromSource, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.ValueToObject (BehaviorDesigner.Runtime.Tasks.Task task, System.Type type, System.Object obj, BehaviorDesigner.Runtime.IVariableSource variableSource, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeObject (BehaviorDesigner.Runtime.Tasks.Task task, System.Object obj, System.Collections.Generic.Dictionary`2[TKey,TValue] dict, BehaviorDesigner.Runtime.IVariableSource variableSource, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeTask (BehaviorDesigner.Runtime.BehaviorSource behaviorSource, System.Collections.Generic.Dictionary`2[TKey,TValue] dict, System.Collections.Generic.Dictionary`2[System.Int32,BehaviorDesigner.Runtime.Tasks.Task]& IDtoTask, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeTask (BehaviorDesigner.Runtime.BehaviorSource behaviorSource, System.Collections.Generic.Dictionary`2[TKey,TValue] dict, System.Collections.Generic.Dictionary`2[System.Int32,BehaviorDesigner.Runtime.Tasks.Task]& IDtoTask, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeTask (BehaviorDesigner.Runtime.BehaviorSource behaviorSource, System.Collections.Generic.Dictionary`2[TKey,TValue] dict, System.Collections.Generic.Dictionary`2[System.Int32,BehaviorDesigner.Runtime.Tasks.Task]& IDtoTask, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeTask (BehaviorDesigner.Runtime.BehaviorSource behaviorSource, System.Collections.Generic.Dictionary`2[TKey,TValue] dict, System.Collections.Generic.Dictionary`2[System.Int32,BehaviorDesigner.Runtime.Tasks.Task]& IDtoTask, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.DeserializeTask (BehaviorDesigner.Runtime.BehaviorSource behaviorSource, System.Collections.Generic.Dictionary`2[TKey,TValue] dict, System.Collections.Generic.Dictionary`2[System.Int32,BehaviorDesigner.Runtime.Tasks.Task]& IDtoTask, System.Collections.Generic.List`1[T] unityObjects) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.JSONDeserialization.Load (BehaviorDesigner.Runtime.TaskSerializationData taskData, BehaviorDesigner.Runtime.BehaviorSource behaviorSource) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.BehaviorSource.CheckForSerialization (System.Boolean force, BehaviorDesigner.Runtime.BehaviorSource behaviorSource) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.Behavior.CheckForSerialization () (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.BehaviorManager.EnableBehavior (BehaviorDesigner.Runtime.Behavior behavior) (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.Behavior.EnableBehavior () (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)
BehaviorDesigner.Runtime.Behavior.Start () (at <9fd26eacf1af4bd8ab9b56956877bd65>:0)

Your documentation says that we can simply set the variables by running this code:

Code:
public class Spawner : MonoBehaviour
{
    public GameObject m_Enemy;

    public void PrefabSpawned(BehaviorTree behaviorTree)
    {
        behaviorTree.SetVariableValue("Enemy", m_Enemy);
    }
}

Yet I cannot really understand how I could make a method that receives a behaviortree as a parameter as I dont know how to send the behaviorTree as a parameter, and where would I send it from? a task? can I reference the the current tree the action/task is in atm? all of this is really unclear and the whole prefab-trees should really be made more clear as it is a fundamental thing. I have now used about 4 hours on trying to make a simple prefab enemy with a behaviorTree and cannot find any solid information or instruction on how to do it properly.

Please could you describe to me here what I have to do - in specific detail without taking assumptions of prior knowledge to how behaviorTrees work - how you go about making a prefab that has a behaviourTree that requires references.

thank you.
 
Can you send me a PM with your Unity version? I can't see anything wrong with your script and I may have already fixed the error. Your image also looks good.

That example won't work without some underlying code calling it, you can get the behavior tree with GetComponent<BehaviorTree>().

Code:
    public void Start()
    {
        GetComponent<BehaviorTree>().SetVariableValue("Enemy", m_Enemy);
    }

I have also updated the docs to include a similar example.
 

Why would you use an external tree if he wants to make changes to it?

In my case I have a flee behavior and an evade behavior to see the differences. I set a global variable to my player in my level manager behavior, and set within distance of the flee behavior to said variable. The flee behavior works as expected however, if I duplicate that object and simply replace flee with evade, it no longer works. The variable does not get sent to the new behavior for some reason. I even changed the behavior name with no success.
 
Last edited:
Why would you use an external tree if he wants to make changes to it?

In my case I have a flee behavior and an evade behavior to see the differences. I set a global variable to my player in my level manager behavior, and set within distance of the flee behavior to said variable. The flee behavior works as expected however, if I duplicate that object and simply replace flee with evade, it no longer works. The variable does not get sent to the new behavior for some reason. I even changed the behavior name with no success.

I moved the find tag player and set variable to within the flee behavior. When I duplicate this it works fine. Just wondering why this method does not work with global variables?
 
If you are using multiple behavior trees at the same time with the same global variable then it will be overwritten by each tree so can lead to unexpected results.
 
If you are using multiple behavior trees at the same time with the same global variable then it will be overwritten by each tree so can lead to unexpected results.

Why would it be overwritten? If I have 1 behavior tree that sets a global variable to the player then pass that variable to all other trees then they should all just read this variable as the player. Why would anything overwrite it? I switch players so I'm trying to get around constantly searching for the player tag in every enemies behavior by just setting 1 global variable as the player and set it every time I switch the player. The same setup works with Playmaker but does not seem to port over well to BD.
 
Top