Odd performance issues when instantiating prefab with behavior tree.

Andrew900460

New member
I have a few prefabs in my Unity project that have Behavior Tree components on them. And I had worked on making it so each of those prefabs used a particular "External behavior tree". So If I made a change to one, it applied to all the others.

Today I've been making an enemy that spawns other enemies when it dies. And I am having this odd issue where there is a slight lag spike when those enemies are created. I checked with Unity's profiler, and the lag does appear to be coming from the Behavior Tree component when it is first being created. The delay is about 20 milliseconds. Which is quite large. And I am creating multiple enemies at the same time as well.

As an extra sanity test, I made a "bare-bones" prefab with only the B.T. Component attached, and 2 other components that the tree needed (because it uses property maps for some variables. I made a test script to spawn the prefab and looked at its profiler time for instantiation. And this time It only took 2 milliseconds.

Also, I should point out that the times I'm getting in the profile are coming from a "time block" that is labeled "Behavior.Start()" Which I imagine is the Start function in the Behavior Tree Component.

And If I were to disable the B.T. component on my actual enemies, and then spawned them at runtime, there would be no lag spike. Then, while running the game in editor, I could manually enable the B.T. component. When I did that, there was no lag spike. So for some reason, I am getting this 20 millisecond lag spike. And according to the testing I've done, that lag spike can be avoided somehow.

Any ideas why I would get this performance issue? My Ai is simple enough right now that I could've written it as just code in a mono behavior. And I know I wouldn't have any performance issues if I did that.
 
Last edited:
Update:

After some more testing, I have discovered that It appears the reason why I am getting this lag spike is because I am using External Behavior Trees. And each time I instantiate a prefab, it has to do some sort of processing to the external tree so it can work in the object. I'm guessing it's doing some deserializing maybe? The documentation section of the website is hinting to me that could be the cause.

So what I did, is I took the nodes of my external tree, copied them into the B.T. component, and removed the External Tree reference from the component. So the tree data is now stored directly in the prefab, which also means now that if I make a change to the external tree, it won't apply to that one prefab. But this makes me wonder...

If a Behavior Tree Dev is reading this, can you tell me if you think its a good idea to instead make special prefabs to hold behavior trees with the component? And then what I would do is "nest" that prefab with the B.T. component inside my other enemy prefabs.

So visually it would be like:

MyEnemy (root gameobject)
|
------ Behavior Tree Ai (child gameobject)
|
------ Main Sprite (child gameobject)
|
------ Body Collider (child gameobject)

And so in this diagram ^ where you see "Behavior Tree Ai". That would be a gameobject that holds the Behavior tree component, and I could configure it to interact with components in the root object instead. And this would allow me to make that a prefab and put it in many objects, and I would not have spawn lag issues, I believe.

Hope this is helpful.
 
External Behavior Trees are independent Scriptable Objects and not attached to prefabs. Is this what you are referring to? With External Behavior Trees I recommend pooling them while the scene is loading in order to boost performance:


With that said, if your design of having multiple child behavior trees works and makes sense for your project then definitely continue with that approach :)
 
External Behavior Trees are independent Scriptable Objects and not attached to prefabs. Is this what you are referring to? With External Behavior Trees I recommend pooling them while the scene is loading in order to boost performance:


With that said, if your design of having multiple child behavior trees works and makes sense for your project then definitely continue with that approach :)
Exactly. Yea, I have prefabs that have Behavior Tree components, and the "external behavior tree" property is set to an External Behavior Tree object that I've made. But I discovered that there is a large lag spike when making prefab instances, but If I don't store the tree in an external behavior tree, there is no lag spike.

But I still want to share behavior trees among many prefabs, but I also don't want to have to pool external trees just so I can instantiate a few enemies at runtime.

While writing this, I figured out a few things and discovered a few other things. If you don't have time, you can skip to my last paragraph, because what I was talking about there is more important. But I do want to get your opinion on the other things I've said below this.

At the link you've shown (External Behavior Trees | Opsive), there is some example code showing that you can create instances of the External B.T. assets. And then you call "Init" to initialize, which I believe includes deserializing the tree data. The purpose of pooling and calling "init" is so the time it takes to call "init" doesn't have to happen when the object is created. So it can happen earlier.
So I had this idea of calling "Init" on the main External behavior tree asset at runtime. And the assumption is that when I make instances of that object, it just copies the data, and I don't have to call Init on each one.

This is a code snippet showing what it is that I was testing.
C#:
GameObject enemyPrefabAsset; // assume this variable has been given a value;

var tree = enemyPrefabAsset.GetComponent<BehaviorDesigner.Runtime.BehaviorTree>();
    if(!tree.ExternalBehavior.Initialized)
        tree.ExternalBehavior.Init();

var newEnemy = Instantiate(enemyPrefabAsset);

So the idea here is that I can call Init only once when I am creating a prefab for the first time, but then every other time after that I don't have to because it was called on the prefab. I have a feeling this is a big no-no. But I've tested this, and it seems to work. As an alternative solution to putting my behavior trees in child game objects.

The other thing that I have discovered, which is a bit odd. But today I turned on my computer and opened my project. And tested the enemy spawning again, but with external behaviors. And there didn't seem to be any 20 milliseconds today. So the lag isn't as big as it was. So it seemed like restarting my project fixed the lag issue for some reason.
 
Top