- Home /
InvokeRepeating("x",x, 3) vs If(Time.deltaTime % 3)
whichone would be better? I am leaning toward the "If statement" as that would allows me to modify the number easily instead of writing a few more line of code for CancelInvoke and start again
Better in what way?
Personally, I would go with the if condition, or a Coroutine, as invoking functions using strings is clumsy and error prone.
so I guess they basically work the same way? and if they are, why would we use Invoke ins$$anonymous$$d of if
Answer by hexagonius · Jul 27, 2018 at 08:48 PM
I think you answered it yourself already. InvokeRepeating is a very easy to use one liner that does just that, fire, wait, repeat. Done. Any more control and you should use the alternative.
Answer by JVene · Jul 27, 2018 at 09:11 PM
if ( Time.deltaTime % 3 )
Is not likely to compile (I'd be surprised). The result of this expression is a float, which the compiler won't consider for a bool required for "if".
I'd have to say, literally interpreted, there's only 1 options "if( Time.deltaTime %3 )" isn't valid.
Yet, what does it actually mean? This code asks for the remainder after division by 3. Nearly every value that you'd happen to read from Time.deltaTime would return some fraction, merely limited to an answer below 3, which would be 3 seconds.
Yet, the value deltaTime represents the time elapsed since the last frame. If that's been more than 3 seconds, something is seriously wrong.
If what you intend is to perform something once every 3 seconds, you must track something like Time.time. Even then, %3 of that value, which is sampled by coincidence relative to any specific time interval, is going to return a non-zero result for all occasions except that rare moment when the time sampled happens to align exactly on the second (nothing but zeros past the decimal), and is a multiple of 3 seconds (so there's no remainder).
In order to get a bool result from tracking time to sense every 3 second interval, you must choose from a few approaches that track time, usually counting down from 3 testing for
It seems clear InvokeRepeating is a nice idea, but as a Unity invention it leaves one issue wanting: it uses a string for the function identifier, and no good way of warning you at compile that the function doesn't exist. There is a way to create an InvokeRepeating interface that uses a delegate, but Unity didn't choose that means. If it did, I would suggest InvokeRepeating avoids cluttering the Update function.
Indeed, most questions like this are focused on the observation that Update threatens to become a wild mess of ifs and elses, each relying on multiple input.get...or member variales. Coroutines and Invoke suggest alternatives, but both are conveniences with overhead.
Most of them follow certain patterns, and countdown is one of them.
In order to avoid making Update or FixedUpdate a wild mess, start by insisting they be written as "executive" functions. By this I mean avoid doing the specific calculations and tests, but write functions for the individual steps. That way, instead of reading through a maze of "if..elseif..elseif" statements that mean nothing, Update becomes a collection of calls to functions like "FiringControl()" or "Steering()" or "FindPath()" or whatever. Put the more specific code that checks bools or manages timers in these functions. Update becomes more sane when it becomes too complex to read through (same for FixedUpdate and others).
That said, some of these patterns are so common that they're repeated in every project you write, and in multiple places within a project. On any occasion that you find yourself repeating code, you're probably in need of creating a class that does that stuff, and using it as a plugin machine.
Imagine, for example, a class that counts time down, then calls a function when that timer expires, and if appropriate, automatically resets the timer to some configured interval. You could use such a class anywhere and everywhere this concept comes up with single executive style function call to the object.
Say I have such a class, RepeatingTimer. I create one as a member of some GameObject, with maybe something like:
FireTimer = new RepeatingTimer( FireCommand, 3 );
In this case, the "FireCommand" is a function delegate parameter. Delegates are variable representing a function call, and the "pointer to a function" is it's name. In the class, I have called it with something like:
fTime -= Time.deltaTime;
if ( fTime <= 0 )
{
FireCommand();
fTime = 3f;
}
So, this is the "old" way, probably in Update, where I'm counting down fTime from 3. When it drops to zero, 3 seconds have passed, so I call FireCommand, then reset fTime. No matter how often Update is called, this makes FireCommand happen every 3 seconds (give or take a deltaTime).
However, if I have created a RepeatingTime class, the class holds a delegate to the FireCommand function. Inside the timer, the delegate is a variable. However, it can be used to call any function the delegate is assigned to call, which makes this timer usable to call any function of the matching signature (in this case, FireCommand takes no parameters and returns void).
Now, in Update I merely say....
FireTimer.DoIt();
Use whatever name you like, but this is inside Update, called every update, to service the timer. DoIt will take care of counting down time, calling FireCommand after 3 seconds, reset the timer, and keep doing that.
There's very little overhead. It is almost like it is writen inline inside update, but it's only 1 line in update.
I can have a list of such timers. If needed to have, say, 10 timers, I could simply loop through the list, call "DoIt" for each one, and now instead of 30/40 lines of counting and checking and calling, I have one loop that services all of the timers (each one being different times and functions to be called).
Upvoted for the good explanation. Another way to handle countdowns is to use Coroutines. You can wait for a specific amount of time within a coroutine using the WaitForSeconds class (see above link). Coroutines also allow you to chain them, that is immediately after a coroutine completes, do this other coroutine.
Also many good Youtube tutorials on coroutines.