Optimization principal 3: Call methods as few times as possible.
Coroutines allow us to write asynchronous code—we can ask a method to go off and calculate something, but the rest of the game can keep on running without having to wait for that calculation to end. Or, we can call a coroutine method for each frame from Update()
and organize the method to complete part of a complex calculation each time it is called.
Note that coroutines are not threads, but they are very handy in that each can progress each frame further. It also allows us to write code that does not have to wait for certain methods to complete before another can begin.
When games start requiring complex computations, such as for artificial intelligence reasoning, it may not be possible to maintain acceptable game performance when trying to complete all calculations in a single frame—this is where coroutines can be an excellent solution.
This recipe illustrates how a complex calculation can be structured into several pieces, each to be completed one frame at a time.
Note: An excellent description of coroutines (and other Unity topics) can be found on Ray Pendergraph's wikidot website http://raypendergraph.wikidot.com/unity-developer-s-notes#toc6.
To spread computations over several frames, follow these steps:
SegmentedCalculation
to the Main Camera:using UnityEngine; using System.Collections; public class SegmentedCalculation : MonoBehaviour { private const int ARRAY_SIZE = 50; private const int SEGMENT_SIZE = 10; private int[] randomNumbers; private void Awake(){ randomNumbers = new int[ARRAY_SIZE]; for(int i=0; i<ARRAY_SIZE; i++){ randomNumbers[i] = Random.Range(0, 1000); } StartCoroutine( FindMinMax() ); } private IEnumerator FindMinMax() { int min = int.MaxValue; int max = int.MinValue for(int i=0; i<ARRAY_SIZE; i++){ if(i % SEGMENT_SIZE == 0){ print("frame: " + Time.frameCount + ", i:" + i + ", min:" + min + ", max:" + max); // suspend for 1 frame since we've completed another segment yield return null; } if(randomNumbers[i] > max){ max = randomNumbers[i]; } else if(randomNumbers[i] < min){ min = randomNumbers[i]; } } // disable this scripted component print("** completed - disabling scripted component"); enabled = false; } }
The randomNumbers
array of random integers is created in Awake()
. Then, the FindMinMax()
method is started as a coroutine. The size of the array is defined by constant ARRAY_SIZE
, and the number of elements to process each frame by SEGMENT_SIZE
.
The FindMinMax()
method sets initial values for min and max and begins to loop through the array. If the current index is divisible by the SEGMENT_SIZE
(remainder 0), then we make the method display the current frame number and variable values and suspend execution for one frame with a yield null
statement. For every loop, the value for the current array index is compared with min
and max
, and those values are updated if a new minimum or maximum has been found. When the loop is completed, the scripted component disables itself.
Some details you don't want to miss:
As well as seeing log texts in the Console panel, you can also access the Unity editor log text file as follows:
~/Library/Logs/Unity/Editor.log
C:UsersusernameAppDataLocalUnityEditorEditor.log
For more information about Unity logs files, see the online manual at http://docs.unity3d.com/Manual/LogFiles.html.
18.224.59.192