You copied the Doc URL to your clipboard.

Application processor optimizations

The following list describes application processor optimizations:

Use coroutines instead of Invoke()
The Monobehaviour.Invoke() method is a fast and convenient way to call a method in a class with a time delay, but it has the following limitations:
  • It uses reflection in C# to find the method to call, this can be slower than calling the method directly.
  • There are no compile-time checks on the method signature.
  • You cannot supply additional parameters.
The following code shows the Invoke() function:
public void Function()
{ 
	[...]
}
Invoke("Function", 3.0f);
An alternative method is to use coroutines. A coroutine is a function of type IEnumerator that can return control to Unity with a special yield return statement. You can call the function again later and it resumes where it left off earlier.
You can call coroutines through the MonoBehaviour.StartCoroutine() method:
public IEnumerator Function(float delay)
{
	yield return new WaitForSeconds(delay);
	[...]
}
StartCoroutine(Function(3.0f));
Changing from the Monobehaviour.Invoke() method to using coroutines provides more flexibility over the parameters passed to the functions dealing with animation states.
Use coroutines for relaxed updates
If your game requires an action every specific time interval, try launching a coroutine in the MonoBehaviour.Start() callback, instead of performing an action every frame in the MonoBehaviour.Update() callback. For example:
void Update()
{
	// Perform an action every frame 
}
					
IEnumerator Start() 
{
	while(true)
	{
		// Do something every quarter of second 
		yield return new WaitForSeconds(0.25f);
	}
}

Note

An alternative use of this technique is to spawn enemies at irregular intervals. Use an infinite loop inside the coroutine that spawns an enemy and generates a random number. Pass the random number to the WaitForSeconds() function.
Avoid hard-coded strings for tags
Avoid hard-coded values for tags because they restrict the scalability and robustness of your game. For example, with tag names, if you refer to the names directly by strings, you cannot easily modify them and you are potentially exposed to spelling errors. For example:
if(gameObject.CompareTag("Player"))
{
	[...]
}				
You can improve this by implementing a special class for tags that exposes public constant strings. For example:
public class Tags
{
	public const string Player = "Player";
	[...]
}

if(gameObject.CompareTag(Tags.Player))
{
	[...]
}				

Note

You can use a Tags class with public constant strings to assist adding new tags in a consistent and scalable manner.
Reduce the number of physics calculations by changing the fixed time step
You can reduce the computational load of physics calculations by changing the fixed time step. Typically, most physics calculations take place at a fixed time step and you can increase or decrease the length of this step.
Increasing the time step decreases the load on the application processor but reduces the accuracy of physics calculations.
You can access the time manager from the main menu: Edit > Project Settings > Time.
The following figure shows the time manager:

Figure 4-1 Fixed timestep settings


Remove empty callbacks
If your code includes empty definitions for functions such as Awake(), Start(), or Update(), remove them. There is an overhead associated with these because the engine still attempts to access them even though they are empty. For example:
// Remove the following empty definition

void Awake()
{

}	
Avoid using GameObject.Find() in every frame.
GameObject.Find() is a function that iterates through every object in the scene. This can cause a significant increase in the main thread size if it is used in the incorrect part of your code. For example:
void Update()
{ 
	GameObject playerGO = GameObject.Find("Player");
	playerGO.transform.Translate(Vector3.forward * Time.deltaTime);
}
A better technique is to call GameObject.Find() on startup and cache the result, for example in the Start() or Awake() function:
private GameObject _playerGO = null ;
				
void Start()
{
	_playerGO = GameObject.Find("Player");
}
				
void Update()
{
	_playerGO.transform.Translate(Vector3.forward * Time.deltaTime);
}
Another alternative is to use GameObject.FindWithTag():
void Update()
{
	GameObject playerGO = GameObject.FindWithTag("Player");
	playerGO.transform.Translate(Vector3.forward * Time.deltaTime);
}

Note

Use a dedicated class called LocatorManager that performs all the object retrievals immediately when the scene finishes loading. Other classes can use this as a service so objects are not retrieved multiple times.
Use the StringBuilder class to concatenate strings
When concatenating complex strings, use the System.Text.StringBuilder class. This is faster than the string.Format() method and uses less memory than concatenation with the plus operator:
// Concatenation with the plus operator
string str = "foo" + "bar";

// String.Format() method 
string str = string.Format("{1}{2}", "foo", "bar");
The System.Text.StringBuilder class:
// StringBuilder class 
using System.Text;

StringBuilder strBld = new StringBuilder(); 
strBld.Append("foo"); 
strBld.Append("bar"); 
string str = strBld.toString(); 
The following figure shows string concatenations:

Figure 4-2 String concatenations


Use the CompareTag() method instead of the tag property

Use the GameObject.CompareTag() method instead of the GameObject.tag property. The CompareTag() method is faster and does not allocate extra memory:

GameObject mainCamera = GameObject.Find("Main Camera");

// Gameobject.tag property
if(mainCamera.tag == "MainCamera")
{
	// Perform an action
}

// Gameobject.CompareTag() method
if(mainCamera.CompareTag("MainCamera"))
{
	// Perform an action
}
The following figure shows the use of CompareTag():

Figure 4-3 Compare tag


Use object pools
If your game has many objects of the same kind that are created and destroyed at runtime, you can use the design pattern object pool. This design pattern avoids the performance penalty of allocating and freeing many objects dynamically.
If you know the total number of objects that you require, you can create them all immediately and disable the objects that are not immediately required. When a new object is required, search the pool for the first unused one and enable it.
When an object is not required anymore, you can return it to the pool. This means resetting the object to a default starting state and disabling it.
This technique can be used with objects such as enemies, projectiles, and particles. If you do not know the exact number of objects that you require, do a test to find how many are used and create a pool slightly bigger than the number you find.

Note

Use object pools for enemies and bombs. This restricts the allocation of those objects to the loading phase of the game.
Cache component retrievals
Cache the component instance returned by GameObject.GetComponent<Type>(). The function call involved is quite expensive.
Properties such as GameObject.camera, GameObject.renderer or GameObject.transform are shortcuts to the corresponding GameObject.GetComponent<Camera>(), GameObject.GetComponent<Renderer>(), and GameObject.GetComponent<Transform>():
private Transform _transform = null;

void Start()
{ 
	_transform = GameObject.GetComponent<Transform>();
}

void Update() 
{
	_transform.Translate(Vector3.forward * Time.deltaTime); 
}
Consider caching the return value of Transform.position. Even if it is a C# getter property, there is overhead associated with an iteration over the transform hierarchy to calculate the global position.

Note

In Unity 5 and higher, the transform component is automatically cached.
Use OnBecameVisible() and OnBecameInvisible() callbacks
Callbacks such as MonoBehaviour.OnBecameVisible() and MonoBehaviour.OnBecameInvisible() notify your scripts if their associated game objects become visible or invisible on screen.
These calls enable you to, for example, disable computational heavy code routines or effects when a game object is not rendered on screen.
Use sqrMagnitude for comparing vector magnitudes
If your application requires the comparison of vector magnitudes, use Vector3.sqrMagnitude instead of Vector3.Distance() or Vector3.magnitude.
Vector3.sqrMagnitude sums the squared components without calculating the root, but this is useful for comparisons. The other calls use a computationally expensive square root.
The following code shows the three different techniques used in comparisons of two positions in space:
// Vector3.sqrMagnitude property 
if ((_transform.position - targetPos).sqrMagnitude < maxDistance * maxDistance) 
{
	// Perform an action 
}

// Vector3.Distance() method
if (Vector3.Distance(transform.position, targetPos) < maxDistance)
{ 
	// Perform an action
} 
					
// Vector3.magnitude property 
if ((_transform.position - targetPos).magnitude < maxDistance) 
{ 
	// Perform an action
}
Use built-in arrays
If you know the size of an array in advance, use the built-in arrays.
ArrayList and List classes have more flexibility because they grow in size the more elements you insert, but they are slower than the built-in arrays.
Use planes as collision targets
If your scene only requires particle collisions with planar objects such as floors or walls, change the particle system collision mode to Planes. Changing the setting to use planes reduces the computations required. In this mode you can provide Unity with a list of empty GameObjects to act as the collider planes.
The following figure shows collision settings:

Figure 4-4 Collision settings


Use compound primitive colliders rather than mesh colliders
Mesh colliders are based on the real geometry of an object. These are very accurate for collision detection but are computationally expensive.
You can combine shapes such as boxes, capsules, or spheres into a compound collider that mimics the shape of the original mesh. This enables you to achieve similar results with much lower computational overhead.
Was this page helpful? Yes No