Disabling unused scripts and objects

Scenes can get pretty busy sometimes, especially when we're building large, open worlds. The more objects invoking code in an Update() method, the worse things will scale and the slower your game becomes. However, much of what is being processed may be completely unnecessary if it is outside of the player's view or simply too far away to matter. This may not be a possibility in large city-building simulation games where the entire simulation must be processed at all times, but it is often possible in first person and racing games, where the player is wandering around a large expansive area, where non-visible objects can be temporarily disabled without having any noticeable effect on gameplay.

Disabling objects by visibility

Sometimes, we want Components or GameObjects to be disabled when they're not visible. Unity comes with built-in rendering features to avoid rendering objects that are not visible by Cameras (Frustum Culling, which is automatic in all versions), and to avoid rendering objects that are hidden behind other objects (Occlusion Culling, to be discussed in Chapter 6, Dynamic Graphics), but this does not affect Components that are non-renderable, such as AI scripts. We must control that behavior ourselves.

This problem can be solved easily by using the OnBecameVisible() and OnBecameInvisible() MonoBehaviour callbacks. As the names imply, these callback methods are invoked when a renderable object has become visible or invisible with respect to the game view and any Cameras in our Scene. In addition, when there are multiple Cameras in a Scene (for example, a local multiplayer game), the callbacks are only invoked if the object becomes visible to any one Camera, and becomes invisible to all Cameras. This means the aforementioned callbacks will be called at exactly the right times to implement this feature.

Since the visibility callbacks relate to and communicate with the rendering system, the GameObject must have a renderable object attached, such as a Mesh or SkinnedMesh. We must ensure that the Components we want to receive the visibility callbacks from are attached to the same GameObject as the renderable object and not some parent or sub-object, otherwise they won't be invoked.

Tip

Note that Unity also counts the hidden camera of the Scene View towards the OnBecameVisible() and OnBecameInvisible() callbacks. If we find that these methods are not being invoked properly during Play Mode testing, make sure to turn the Scene View Camera away from everything.

To enable/disable individual components with the visibility callbacks, we can add the following methods:

void OnBecameVisible() { enabled = true; }
void OnBecameInvisible() { enabled = false; }

And, to enable/disable the entire GameObject the Component is attached to, we can implement the methods this way instead:

void OnBecameVisible() { gameObject.SetActive(true); }
void OnBecameInvisible() { gameObject.SetActive(false); }

Disabling objects by distance

In other situations, we want Components or GameObjects to be disabled after they are far enough away from the player, such that they may be barely visible, but too far away to matter. A good candidate for this type of activity is roaming AI creatures that we want to see at a distance, but where we don't need it to process anything.

The following code is a simple Coroutine that periodically checks the total distance from the target object and disables itself if it strays too far away from it:

[SerializeField] GameObject _target;
[SerializeField] float _maxDistance;
[SerializeField] int _coroutineFrequency;

void Start() {
  StartCoroutine(DisableAtADistance());
}

IEnumerator DisableAtADistance() {
  while(true) {
    float distSqrd = (Transform.position - _target.transform.position).sqrMagnitude;

    if (distSqrd < _maxDistance * _maxDistance) {
      enabled = true;
    } else {
      enabled = false;
    }

    for (int i = 0; i < _coroutineFrequency; ++i) {
      yield return new WaitForEndOfFrame();
    }
  }
}

We should assign the Player object (or whatever object we want it to compare with) to the _target field in the Inspector, define the maximum distance in _maxDistance, and modify the frequency with which the Coroutine is invoked by using the _coroutineFrequency property. Any time the object goes further than _maxDistance distance away from the object assigned to _target, it will be disabled. It will be re-enabled if it returns within that distance.

A subtle performance-enhancing feature of this implementation is comparing against distance-squared instead of the raw distance. This leads us conveniently to our next tip.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.198.81