Unity/Timing
For those of you coming from a more traditional academic programming language/software, Unity may be a little confusing in terms of when and where things happen. Unlike, say, Python, there is no main loop to be called explicitly. Instead, Unity scripts are derived from the MonoBehaviour class, which handles the order of execution and any update loops per object. Below is a list of key functions that you will likely have to use to get things done or measured.
Awake()
Called when the object the script is attached to is first loaded into a scene. This is where you would initialize any variables or states that you may need before the application starts, and where to set up a Singleton, for example. If there are multiple MonoBehaviour scripts in the scene, the order in which they call Awake() is not deterministic, so if one script needs to interact with another, ideally you will set that up in the Start() function.
Functions
OnEnable()
Called every time the script is enabled. If the script is enabled at the start of the scene, this will fire after Awake(), but potentially before the Awake() of a different script. Use this function to initialize objects that may be disabled and enabled multiple times during the game, or objects that get instantiated during runtime.
Start()
Called on the frame when the script is enabled, before any update methods are called the first time. If the script is active at the start of the scene, Start() will fire only after all enabled scripts have called Awake() and OnEnable().
Update()
Unity's main update loop, called every frame if the script is enabled. Because it is tied to the game's frame rate, time between Update() calls is variable.
LateUpdate()
Called after Update() and any coroutine and animation logic. This is mainly used for overriding animation logic.
FixedUpdate()
Independent loop working at a fixed interval (default 50 Hz). This is mainly used for Unity's physics system, but can be used for anything that should not rely on frame rate.
StartCoroutine()
Starts a coroutine (IEnumerator) for cases where you want to wait for something (time or event) and not block the main loop.
InvokeRepeating()
Starts an independent timer that calls the specified function at the specified rate.
OnDisable()
Called when the script gets disabled.
Timing Accuracy
We have done some preliminary tests looking into the timing accuracy of Unity. Because the main Update loop is tied to the frame rate, it should not be used to measure any time-critical data, but it is useful to trigger something the moment something is seen on screen. For fixed-interval timing, FixedUpdate and InvokeRepeating are most reliable, even up to higher sampling rates (1000Hz), though it is advised not to change the FixedUpdate rate because it is tied to Physics logic. Using a while loop in a coroutine with the WaitForSeconds() method is not as accurate in our tests. Likewise, C# system native timers (Timer and ThreadedTimer) are not always reliable.
We will investigate timings in further detail and share the results. In the meantime you can contact the TSG if you have any questions about what to use for logging your data.