What's your favorite method for scripting recurring events?

Recurring events are something I’ve been scripting for a while, but I’m never really sure of the best way to script it. And by recurring events I mean anything that will happen periodically without user intervention - so things like eyes blinking, NPCs wandering, lights flickering, etc.

I’ve seen this implemented at least 4 different ways (shown below). I typically do #1. I like the compactness of #4, but don’t like passing the function name as a string and not being able to pass parameters. I’m also uneasy about Invoke because it’s not well-documented (is it a Coroutine? Can I stop it once I start it? Can I use InvokeRepeating multiple times? etc.) and does a little too much “behind-the-scenes” for my peace of mind.

Anyway, I was wondering if anybody else has any strong opinions on the best way to handle these kinds of events.

#1)

void Start( ) {
   StartCoroutine ( Wander( ) );
}

IEnumerator Wander( ) {
   while ( true ) {
      MoveSomewhere( );
      yield return new WaitForSeconds( 5.0f );
   }
}

#2)

void Start( ) {
   StartCoroutine ( Wander( ) );
}

IEnumerator Wander( ) {
   MoveSomewhere( );
   yield return new WaitForSeconds( 5.0f );
   StartCoroutine( Wander( ) );
}

#3)

private float timeOfNextWander;

void Start( ) {
   timeOfNextWander = Time.time + 5.0f;
}

void Update( ) {
   if ( Time.time >= timeOfNextWander ) {
      MoveSomewhere( );
      timeOfNextWander = Time.time + 5.0f;
   }
}

#4)

void Start( ) {
   InvokeRepeating( "MoveSomewhere", 0.0f, 5.0f );
}

I think all of them are fine, though I don’t like #2 as much as the others since I personally don’t like those self-invoking functions.

For the most part I think it is again up to the real thing you want to achieve. For example, #3 is in my eyes the best way to implement something like a weapon were you only have a certain firing frequency.

#4 is nice if you want to start a certain recurring event in an Update()-like fashion some time during the game without the “real” Update() function being called until then.

#1 is good in case you want to fire events in a certain interval and not like in Update() every frame.

So everyone has it’s pros and cons, yet as mentioned I use #2 the least as I don’t see any advantage for that, especially compared to #1, which is more controllable in my eyes.

But bottom line is: None of these is actually “wrong”. It depends on the situation and one might fit better than others.

As the noobiest of noobs, I just stick with my for loops and timing functions.

I find I use option #3 during development so I can easily access the timing variable from the inspector. If the routine can’t be evaluated into a run / no run and it takes up a lot of time then I start thinking about not running it in the update and using InvokeRepeating. Perhaps it’s my code style but I seem to run into little gotchas and end up writing extra guard / sanity check code in my invoked statements which can possibly distract me from my main goal if I let it.

InvokeRepeating.

Probably #1 mostly when I just want something to run forever. I’ve never thought of #2, interesting!

Thanks for the feedback guys.

One thing that did occur to me after posting this… if the recurring event needs to run script in more than a single frame then #1 and #2 quickly become the best choices. Eyes blinking and flickering lights would be good examples of this. Blinking eyes logic would be something like, wait 5 seconds, close eyes, wait 0.5 seconds, open eyes, repeat. That’s the kind of thing best suited to a coroutine with yield statements.

You could use this lib (Timer class).

Usage:

using eDriven.Core.Util;

void Start() {

    // 1. blinking timer
    Timer t = new Timer(1); // tick each second
    t.Tick += delegate { Debug.Log("Eyes blinking"); };
    t.Start();

    // 2. moving timer
    Timer t2 = new Timer(2.5); // tick each 2.5 seconds
    t2.Tick += delegate { MoveSomewhere(); };
    t2.Start();
}

Really worth a try!

Another timer example here.

Probably use something like #3 - invoke repeating is fine if you have something that is repeating at a set interval, but in my games thats usually just a timer, most other things have slight off sets or randomness to bring them to life.

Something like this:

var frameRate : float; //this could be inherited from a master setting
private var frameFire : float;
var metronome : boolean;

function Update() {
	if ( Time.time >= frameFire ) {
		frameFire = Time.time + frameRate;
		//see the rate in you console for fun:
		if (metronome) {
			Debug.Log("tick");
			metronome = false;
		} else {
			Debug.Log("tock");
			metronome = true;
		}
	}
}