Best code for repeated-at-interval things

I have something that happens ever x-y seconds. In my case, random environment sound effects, but it could be other things as well.

I’m trying to understand what’s the best way to handle that:

  • Use Invoke() with recursion, i.e. in Start() I call a function that then does my thing and Invoke()s itself with a random delay
  • Use a Coroutine with an endless loop and a yield WaitForSeconds()
  • Use Update() with a timer variable

I’m sure some of these create more overhead than the others, and if I have a hundred or so of them running at once that might actually matter. So which is the recommended solution and why?

Well, you could always test it yourself, no need to wait for a response from someone who has. Seems easy enough to make a test project for.

Tests are one thing, but a complex system like Unity may well behave differently when things are not isolated. That’s why I’m looking for an answer with explanation.

I don’t believe Unity does any “secret optimizations” for this in the background, but perhaps someone knows more than me. Back to the original problem though, it would be better to just create a manager which handles all the sounds for you, as the overhead from having so many scripts would be a lot.

I’m not talking about secrets. And in my case, due to all those game objects being very dynamic, I don’t think a manager would be the better solution. I’ve got plenty of managers where it makes sense, here it doesn’t.

You can use magic black box stuff like Invoke / InvokeRepeating… but WHY? Those APIs bring zero value to this problem, plus now you have inherited 100% of the magic inside them, which is not necessarily obvious in all cases.

This construct will always work, as long as you meet all the conditions for Update() to be called every frame.

float yet;
const float interval = 1.0f;

void Update()
{
  yet += Time.deltaTime;

  if (yet >= interval)
  {
    yet -= interval;

    CallMyThing();
  }
}

There’s NOTHING hard about writing the above, nothing that InvokeRepeating() “gets you out of.”

Isn’t dynamic sort of a boolean? Something either changes on a given frame or not… I mean I suppose you could change 10 times per frame, but the only one the user will see is the final one!

2 Likes

I read elsewhere that calling Update has always some overhead so Coroutine might be better here but since I am no expert in that matter I would like to hear the “solution” as well :slight_smile:

Alas, you have been lied to. They are equivalent.

It’s all one thread, one big long happy “does everything in scripting thread” when you’re in Unity scripting land.

Here is some timing diagram help:

https://docs.unity3d.com/Manual/ExecutionOrder.html

would just do a Update like Kurt already did. Just keep it simple, i often have a few things in update that have conditions and do not execute everyframe, but like every second or some other interval.

also do not worry about performance to the point it effects your design, unless you already profiled and proven what the problem is.

I created a timer manager for similar requirements. It’s pretty crude but did what I wanted right off the bat so I’ve not gotten around to improving it.

To set up a new timer I do this:

      FunctionTimerDetail functionTimerDetail = new FunctionTimerDetail();
            functionTimerDetail.Function = () => gameManager.BattleManager.RunBattleRound(battleId);
            functionTimerDetail.Count = 10;
            functionTimerDetail.Interval = 1.0f;
            functionTimerDetail.CallImmediately = true;

            uint timerId = gameManager.TimerManager.AddFunctionTimer(functionTimerDetail);

Randomisation could be added to the detail and left to the timer manager to worry about executing it.