I ran into this issue last week, and I think I figured out a succesful workaround for my specific case.
I’m using PoolManager to spawn enemies that have animation components on them, and same as for Futurerobot, they caused lagspikes each time PoolManager spawned them.
After reading here that switching the gameObject between Enabled/Disabled states brought me to replace all of PoolManager’s internal calls to SetActiveRecursively with this custom function:
static Vector3 inactivePosition = new Vector3(0f, -100f, -100f);
internal bool DespawnInstance(Transform xform) // Existing method in SpawnPool.cs
{
...
// Deactivate the instance and all children
//xform.gameObject.SetActiveRecursively(false);
// Deactivate the all child components, except for animations
SetTransformActiveRecursively(xform, false);
xform.position = inactivePosition;
...
}
void SetTransformActiveRecursively(Transform transform, bool active)
{
SetTransformActive(transform, active);
if (transform.childCount > 0)
{
for (int i = 0; i < transform.childCount; i++)
SetTransformActiveRecursively(transform.GetChild(i), active);
}
}
// Flags used to find the 'enabled' property on Unity components that don't expose it.
const System.Reflection.BindingFlags flags =
System.Reflection.BindingFlags.GetField |
System.Reflection.BindingFlags.SetField |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Instance;
void SetTransformActive(Transform transform, bool active)
{
Animation[] animations = transform .GetComponents <Animation >();
if (animations .Length > 0)
{
Animation anim;
for ( int i = 0; i < animations .Length; i ++)
{
anim = animations[i];
if (active)
anim .Sample();
else
anim .Stop();
}
Component[] components = transform.GetComponents< Component> ();
Component component;
System .Type type;
System .Reflection .PropertyInfo property;
for ( int j = 0; j < components .Length; j ++)
{
component = components[j];
type = component .GetType();
if ( !(type == typeof( Animation)) )))
{
property = type .GetProperty( "enabled", flags);
if (property != null)
property .SetValue(component, active, null);
}
}
}
else
transform .gameObject .active = active;
}
This treats gameObjects with an Animation component on them differently. It doesn’t enable/disable those objects, instead just starting/stopping animation, and individually disabling components that have the ‘enable’ flag. Calling Animation.Sample forces the RebuildInternalState call, and since the SetActiveRecursively method is triggered at startup for each preloaded prefab, the overhead of the call is moved to startup as well.
Oh, and Unity’s inheritance hierarchy for it’s own components (SkinnedMeshRenderer, Animation) is weird. They don’t inherit from a baseclass that publically exposes the ‘enabled’ flag, which forces this bit of code to use reflection.
Edit: Oops, I forgot to include the actual recursive fuction, definition of the binding flags used, and the bit that moves inactive objects to some offscreen point.