Optimization principal 3: Minimize the number of enabled objects in a scene. Sometimes we may not want to completely remove an object, but we can identify times when a scripted component of an object can be safely disabled. If a Monobehaviour
script is disabled, then Unity no longer needs to send the object Update()
and OnGUI()
messages for each frame.
For example, if a non-player character (NPC) should only demonstrate some behavior when the player can see that character, then we only need to be executing the behavior logic when the NPC is visible—the rest of the time we can safely disable the scripted component.
Unity provides the very useful events OnBecameInvisible()
and OnBecameVisible()
, which informs an object when it moves out of and into the visible area for one or more cameras in the scene.
This recipe illustrates the following rule of thumb: if an object has no reason to be doing actions when it cannot be seen, then we should disable that object while it cannot be seen.
To disable objects to reduce computer processing "workload" requirements, perform the following steps:
Character Controller
package.// file: DisableWhenInvisible using UnityEngine; using System.Collections; public class DisableWhenInvisible : MonoBehaviour { public Transform player; void OnBecameVisible() { enabled = true; print ("cube became visible again"); } void OnBecameInvisible() { enabled = false; print ("cube became in-visible"); } private void OnGUI() { float d = Vector3.Distance( transform.position, player.position); GUILayout.Label ("distance from player to cube = " + d); } }
player
.When visible, the scripted DisableWhenInvisible
component of the cube recalculates and displays the distance from itself to the transform of the 3rd Person Controller, via the player
variable in the OnGUI()
method for each frame. However, when this object receives the OnBecameInvisible()
message, the object sets its enabled
property to false
. This results in Unity no longer sending Update()
and OnGUI()
messages to the object, so the distance calculation in OnGUI()
is no longer performed, thus reducing the game's processing workload. Upon receiving the OnBecameVisible()
message, the enabled
property is set back to true
, and the object will then receive Update()
and OnGUI()
messages for each frame. Note that you can see the scripted component become disabled by seeing the blue "tick" in its Inspector checkbox disappear, if you have the cube selected in the Hierarchy panel, when running the game.
The following are some details you don't want to miss:
Another common situation is that we only want a scripted component to be active if the player's character is nearby (within some minimum distance). In these situations, a sphere collider can be set up, and the scripted component can be enabled only when the player's character enters that sphere. This can be implemented using the OnTriggerEnter()
and OnTriggerExit()
events; for example:
private void OnTriggerEnter(Collider hitObjectCollider) { if (hitObjectCollider.CompareTag("Player")) enabled = true; } private void OnTriggerExit(Collider hitObjectCollider) { if (hitObjectCollider.CompareTag("Player")) enabled = false; }
In some cases you can go one step further, and make the parent GameObject that contains the scripted component "inactive". This is just like deselecting the checkbox next to the GameObject in the Inspector.
To deactivate the parent GameObject, you set its active property to false
:
void OnBecameInvisible() { gameObject.SetActive(false); print ("cube became in-visible"); }
Note, however, that an inactive GameObject does not receive any messages, so it will not receive the OnBecameVisible()
message; and this may not be appropriate for every object that is out of sight of the camera. However, when deactivating objects is appropriate, a larger performance saving is made over simply disabling a single scripted Monobehaviour
component of a GameObject.
The only way to reactivate an inactive object is for another object to set the GameObject's active property back to true
. The following script, when added to an active GameObject (such as terrain or controller), will display a button to demonstrate how an inactive object can be reactivated. For this script to work, the public cubeGO
variable must be set by dragging the cube over the variable in the Inspector:
// file: MakeCubeActive.cs using UnityEngine; using System.Collections; public class MakeCubeActive : MonoBehaviour { public GameObject cubeGO; private void OnGUI(){ bool makeCubeActiveButtonClicked = GUILayout.Button("make cube active"); if( makeCubeActiveButtonClicked ) cubeGO.SetActive(true); } }
3.139.83.96