Assign ExternalBehavior at runtime not working ?

orlandobatista

New member
Hi,

I'll try to explain what I'm trying to achieve and what's going on.

So, here's my case:
I have an AI that have to move to a point A to a point B. It can be blocked dynamically by the player and it has spells that it can use to destroy the barrier so it can continue it's path.
I have more than one type of this AI with only one difference: the conditions to use it's spells. So, I decided to have an ExternalBehaviour contaning the decisions to use it's spells and a main behaviour that is shared among all of them.

So, I did the following code to test this logic:

C#:
using System.Linq;
using UnityEngine;
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;

public class TestBehaviourDesigner : MonoBehaviour
{
    BehaviorTree behaviourTree;

    [SerializeField] ExternalBehavior mainBehaviourReference;
    [SerializeField] ExternalBehavior obstructionBehaviourReference;
    [SerializeField] ExternalBehavior abilitySelectorReference;

    void Start()
    {
        BehaviorTree behavior = gameObject.AddComponent<BehaviorTree>();
        behavior.StartWhenEnabled = false;
        behavior.DisableBehavior();

        ExternalBehavior mainBehaviourInstance = Instantiate(mainBehaviourReference);
        ExternalBehavior obstructionBehaviourInstance = Instantiate(obstructionBehaviourReference);
        ExternalBehavior abilitySelectorInstance = Instantiate(abilitySelectorReference);

        mainBehaviourInstance.FindTasksWithName("Obstruction").Select(x => x as BehaviorTreeReference).ForEach(x => SetExternalBehaviorTree(x, obstructionBehaviourInstance));
        mainBehaviourInstance.FindTasksWithName("Ability").Select(x => x as BehaviorTreeReference).ForEach(x => SetExternalBehaviorTree(x, abilitySelectorInstance));
        obstructionBehaviourInstance.FindTasksWithName("Ability").Select(x => x as BehaviorTreeReference).ForEach(x => SetExternalBehaviorTree(x, abilitySelectorInstance));

        behavior.ExternalBehavior = mainBehaviourInstance;
        behavior.EnableBehavior();
    }

    void SetExternalBehaviorTree(BehaviorTreeReference behaviorTreeReference, ExternalBehavior externalBehavior)
    {
        behaviorTreeReference.externalBehaviors = new ExternalBehavior[] { externalBehavior };
    }
}

And it in fact works, but seems that behavior.ExternalBehavior = mainBehaviourInstance isn't working as I expected.
If I select the Behaviour that I created at Runtime, the reference is there:

1509


But when I select the Character's Behaviour, which is the actual AI, it's not:


1510


And obviously I got an "ArgumentOutOfRangeException".
What am I doing wrong here?

Sorry for this newbie question and thanks in advance!
 
When the tree is enabled all of the Behavior Tree References are consumed by the external tree that they represent. So if you want to replace the external behavior tree value later on you'll need to make sure you are starting with a fresh tree.

In this case though can you just subclass the BehaviorTreeReference task and provide a custom override for GetExternalBehaviors? This will allow you to choose at runtime which subtree to run.
 
To be honest, I don't really got it what you meant with "starting with a fresh tree" but the solution that you proposed solve the problem very well.
Thanks for your support!
 
Top