How to get precise timer

Using the function WaitForSeconds doesn’t seem to produce exact results. Especially when waiting for milliseconds instead of seconds. Is there some other way to let a function wait a specific time?

Example:

var waitingtime : float = 0.1;
var i : int;
@HideInInspector()
var time1 : float = 0;
@HideInInspector()
var time2 :float = 0;
@HideInInspector()
var deltatime : float = 0;

function Start(){
	for (i = 1; i < 16; i++){
		time1 = Time.time;
			yield WaitForSeconds (waitingtime);
		time2  = Time.time;
		deltatime = time2-time1;	
		Debug.Log("Attempt No: " +i +" ;Waited time: " +deltatime +"s - it should be: " +waitingtime +"s.");	
		yield WaitForSeconds(1); //Pause until next round - to give debugger a bit refresh-time.
	} //end for i
} //endfunc Start

This script, attached to some object produces an output similar to this, after hitting the Start-Button in Unity:

Attempt No: 01 ;Waited time: 0.3533334s

  • it should be: 0.1s.

Attempt No: 02 ;Waited time: 0.1527811s

  • it should be: 0.1s.

Attempt No: 03 ;Waited time: 0.1974149s

  • it should be: 0.1s.

Attempt No: 04 ;Waited time: 0.1044042s

  • it should be: 0.1s.

Attempt No: 05 ;Waited time: 0.1999474s

  • it should be: 0.1s.

Attempt No: 06 ;Waited time: 0.2078395s

  • it should be: 0.1s.

Attempt No: 07 ;Waited time: 0.1046262s

  • it should be: 0.1s.

Attempt No: 08 ;Waited time: 0.1062851s

  • it should be: 0.1s.

Attempt No: 09 ;Waited time: 0.1296844s

  • it should be: 0.1s.

Attempt No: 10 ;Waited time:
0.1247978s - it should be: 0.1s.

Attempt No: 11 ;Waited time:
0.1004639s - it should be: 0.1s.

Attempt No: 12 ;Waited time:
0.1252518s - it should be: 0.1s.

Attempt No: 13 ;Waited time:
0.1074142s - it should be: 0.1s.

Attempt No: 14 ;Waited time:
0.1060486s - it should be: 0.1s.

Attempt No: 15 ;Waited time: 0.217804s

  • it should be: 0.1s.

It’s easy to see that it rarely pauses for the desired time (4 times out of 15 attempts).

I tried writing a custom script but I can’t use it with the yield-command:

function WaitForMilliSeconds(ms : float){
	var timecapture1 : float = 0;
	var timecapture2 : float = 0;
	ms = ms / 1000;	
	timecapture1 = Time.time;
	timecapture2 = timecapture1;
	while (timecapture2-timecapture1 < ms){  // = Until [difference] >= ms
		timecapture2 = Time.time;		
	}//went
}//Endfunc WaitForMilliSeconds

So when I call this function with yield now:

	yield StartCoroutine(WaitForMilliSeconds(100));

The compiler says:

BCE0023: No appropriate version of ‘UnityEngine.MonoBehaviour.StartCoroutine’ for the argument list ‘(void)’ was found.

What am I doing wrong? Isn’t it what yield and Coroutine is for? The script shall pause until the function finshes (without slowing down the whole game).

I think you are misunderstanding what coroutines do, Unity doesn’t multithread coroutines at all which is causing the inconsistent yield results. (Didn’t you ever wonder why everything is magically threadsafe?)

Unity does its normal update loop of:

  • FixedUpdate()
  • Call coroutine that has yielded WaitForFixedUpdate until it yields again
  • Update()
  • Call all coroutines that have yielded for atleast long enough except WaitForFixedUpdate until it yields again
  • LateUpdate()
  • RenderStuff()

When your coroutine is called, nothing else is done until you yield, trying to use a busy wait in a coroutine will cause no more frames to be rendered until you yield again which is a very bad idea.

I haven’t delved into real threading in Unity yet, but this is much more hardcore stuff that unity won’t hold your hand through like coroutines. Which opens up a can of worms around thread safety and deadlocks which aren’t to be taken lightly.

Here are the docs on when coroutines are called:

  • yield; The coroutine will continue after all Update functions have been called on the next frame.
  • yield WaitForSeconds(2); Continue after a specified time delay, after all Update functions have been called for the frame
  • yield WaitForFixedUpdate(); Continue after all FixedUpdate has been called on all scripts
  • yield WWW Continue after a WWW download has completed.
  • yield StartCoroutine(MyFunc); Chains the coroutine, and will wait for the MyFunc coroutine to complete first.

Waiting for an EXACT amount of time is impossible. (shcipwa’s answer gets this quite well). Although even with threads you’ll still be a little out (analogue vs digital). The real question is what are you trying to achieve? The correct approach will probably be see how far “over” you went and deal with it somehow.

For example, if you are writing the 0.1 part of a clock (yes, I actually came across a clock written using logic like this! A 60s game took about 70s, varying wildly depending on the platform >.>; ), you need to carry over the missed part (or use (int)(Time.time % 0.1) or something)

Also, to get such varying results, you might have other performance problems… Are you doing some heavy calculations in this waiting time? To wait 0.31s on a 0.1s wait you are running at less than 5fps…

If you are doing physics calculations you might be able to used FixedUpdate(). The deltaTime in fixed update is fixed (but its also fake! But then so are most of the time functions…)

So back to the question: You can’t. You’ll have to fake it. What are you trying to do?

I know im 6 years to late and nobody will probably answer but would it be possible to take the time from an online timer with an api?