Changing External Behaviors in runtime Performance Spike

aleksej80

New member
Hi.

I have performance problems when switching External Behaviors on BehaviorTree component in runtime. There is a spike on EnableBehavior

Right now I have cut up one huge tree into smaller ones, cuz its clunky to debug and because editor can only handle so much.
So my npcs have like 5 types of behaviors that I would like, which are all seperated in external behaviors and there is more than one npc ofcourse.

I have a behaviorController script which does a bunch of things that are called each frame and really shouldn't be in a behavior tree as well as handling and switching external behaviors. It has a reference to the BehaviorTree component and it also has a pool of external Behaviors.

Right now each npc creates his own pool of External Behaviors that it can use and switches them when they should in run time by disabling Behavior Tree, setting external behavior and enabling back. Same as in documentation example.

As far as I can tell when I'm Enabling the BehaviorTree, it basically itirates through all the node structure again, even though I Instantiated External Behavior b4 hand.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

I'm thinking of pooling BehaviorTrees instead of External Behaviors. Would that work? Is it possible? Would it be more performant?

Did I go wrong about this? Should I just make gameObjects on npc prefab each with its own BehaviorTree component and then have behaviorController script pause/restart/start them based on my internal logic? But when the behaviorTree is paused and enabled again, it calls EnableBehavior again and iterating through whole node structure again, thus I achieve nothing by this? or no? If paused and resumed it will also call all OnAwake functions again? or no?

What exactly is in BehaviorSource? Node structure? Could I just pool that? Could I just directly set BehaviorSource? That pool could than be not just for an instance of npc, but for all npcs that use certain type of behavior --> thus certain type of node structure, but possibly each with different vars values that would need to be set on behavior switch or actually just read in runtime from my behaviorController script, since I don't use sharedVariables.

Does any of this makes sense or am I just confused?

Actually, my question is: how to approach this problem?

Also right now, I'm not pooling npcs prefabs, because I'm not worried about onStart spike, yet. Because of project workflow, it will be added later. I'm just worried about changing behavior spike for now.

I also tried checking the asynch load checkbox, but it gives me an error: An item with the same key has already been added. Key: "name of the behavior I set on start"


Thank you
 
I'm thinking of pooling BehaviorTrees instead of External Behaviors. Would that work? Is it possible? Would it be more performant?
Yes - that will definitely help. This page has an example:


When the behavior tree is enabled on the specific GameObject it has to setup the correct references for that GameObject, but by pooling the external trees you are no longer having to deserialize the tree.
 
I though I am already doing this. For each npc --> I have one BehaviorTree component and I have a pool of many ExternalBehavior-s and as my npc goes to different behavior I change the ExternalBehavior(I use the one from the pool) of that one Behavior Tree component. When the BehaviorTree component is Enabled again with new ExternalBehavior(from the pool), the spike happens.

Perhaps I am not correctly interpreting the example?

And now I'm thinking of having on each npc prefab --> like 5-7 BehaviorTree components each with its own ExternalBehavior that never changes and just start/pause/restart those, instead of switching multiple ExternalBehaviors on just one BehaviorTree component. However I would still need to call EnableBehavior, which It seems like its the root of the problem.

It seems to me that whenever EnableBehavior is called the LoadBehaviorComplete also gets called. I made sure that when I call DisableBehavior(true) I pass the true bool and I checked the "Pause when Disabled" checkbox.

1585055693164.png

Looking at the source code it seems to me like this "pausedBehaviorTrees.TryGetValue( behavior, out behaviorTree )" never returns true and that my tree never gets added to pausedBehaviorTrees. On line 312 in BehaviorManager.cs I am using latest source code that I could download.

Am I pausing it wrong? Or is that just how it works? Every time there is a new ExternalBehavior it just does that? Because if yes, having multiple BehaviorTree components with just one ExternalBehavior that never changes would solve this as far as I can tell. or nah?
 
Am I pausing it wrong?
When the behavior tree is paused it should be added to the dictionary of paused behavior trees. Can you insert a breakpoint within DisableBehavior and see why it's not being added to that list?

Because if yes, having multiple BehaviorTree components with just one ExternalBehavior that never changes would solve this as far as I can tell. or nah?
Yes, having multiple Behavior Trees that you enable/disable would also be a solution.
 
Well after debugging it seems to me that it's just made to work this way. So what is even the point of pooling ExternalBehaviors.
It's fine really, I'm just gonna do the multiple BehaviorTrees thingy, I did a test and it was fine. Frankly having the example of pooling ExternalBehaviors in documentation is a bit confusing, since it seems like its not the optimal thing to do.
 
Top