• RuntimesUnity
  • Why does FPS drop when activating a character?

The main idea is to disable the enemy outside the camera.

On the stage I created 2 objects:

1) Enemy - a “container” for the enemy.
The EnemyController script is connected to it. It has Box Collider 2D isTrigger.

2) EnemyCharacter - enemy.
This object is nested within the Enemy object.
This is an object of type GameObject->Spine->SkeletonAnimation
The EnemyCharacterController script is connected to it.

My camera has Box Collider 2D isTrigger with Rigidbody 2D Kinematics.

When the camera collider intersects the Enemy collider (the "container" for the enemy), the SetActiveSkeletonCharacter method is called. It activates the EnemyCharacter object.

At this moment there is a freeze and a drop in FPS.
Based on the profiler, the freeze is the fault of Spine.

Why does activating a Spine object cause a drop in FPS?

public class EnemyController : MonoBehaviour
{
// Spine->Skeleton Animation Object (Character).
[SerializeField] GameObject skeletonCharacter;

private void Awake()
{
// Initially disable the character.
SetActiveSkeletonCharacter(false);
}

// Enable or disable a character.
private void SetActiveSkeletonCharacter(bool enableSkeletonCharacter)
{
skeletonCharacter.SetActive(enableSkeletonCharacter);
}

// Enable the character object.
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("CameraView"))
SetActiveSkeletonCharacter(true);
}
}

Related Discussions
...

Activating a Spine object can cause a drop in FPS due to the overhead associated with initializing and updating the skeleton animation. When you activate the EnemyCharacter object, the Spine runtime needs to perform several tasks, such as calculating vertex positions, updating bone transforms, and potentially uploading textures to the GPU. These operations can be computationally expensive, especially if the skeleton is complex or if multiple skeletons are activated simultaneously.

Here are some suggestions to mitigate the FPS drop:

  1. Preload and Pooling: Instead of activating and deactivating the skeletons, consider preloading them and using object pooling. This way, the skeletons are already initialized, and you can simply enable or disable their rendering and logic without the overhead of reinitialization.

  2. Optimize Skeleton Complexity: Reduce the number of bones, vertices, and weights in your skeletons. Use the "prune" feature to remove unnecessary vertex transforms. This will reduce the computational load when the skeleton is activated.

  3. Use Binary Export: Export your skeleton data in binary format (.skel.bytes) instead of JSON. Binary data is faster to load and parse, which can help reduce the initialization time.

  4. Update When Invisible: Configure your SkeletonAnimation component to not update when the skeleton is not visible. This can be done by setting the Update When Invisible parameter to false.

  5. Distribute Initialization: If you have multiple skeletons to activate, distribute their initialization over multiple frames to avoid a single frame spike.

Here is an example of how you might implement object pooling and preloading:

public class EnemyController : MonoBehaviour
{
    [SerializeField] GameObject skeletonCharacterPrefab;
    private GameObject skeletonCharacterInstance;

    private void Awake()
    {
        // Preload the character instance
        skeletonCharacterInstance = Instantiate(skeletonCharacterPrefab);
        skeletonCharacterInstance.SetActive(false);
    }

    private void SetActiveSkeletonCharacter(bool enableSkeletonCharacter)
    {
        skeletonCharacterInstance.SetActive(enableSkeletonCharacter);
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("CameraView"))
            SetActiveSkeletonCharacter(true);
    }
}

By preloading the skeleton character, you avoid the initialization overhead during gameplay, which should help reduce the FPS drop.