0
\$\begingroup\$

I'm making a game and I want an update method to be called every 120th of a second. I've looked up timers but they start the timer after the function has returned, but I want the timer to start when the function is called. Any suggestions?

\$\endgroup\$
2
  • \$\begingroup\$ What should happen when the timer is up and your function is not over? Should it 1) wait, 2) skip the call, 3) run in parallel? \$\endgroup\$
    – Theraot
    Apr 28, 2017 at 23:34
  • \$\begingroup\$ Ideally 3, but more than likely 2 \$\endgroup\$ Apr 28, 2017 at 23:35

1 Answer 1

0
\$\begingroup\$

I do not know what timer solution you are using, in fact, I am not very familiar with the options available to you.


Let us say you have a re-scheduled timer of the form (pseudo code):

int callback()
{
    doSomething();
    schedule_timer(callback, interval); // interval declared outside
}

In this case, callback isn't really running at interval, but at interval plus the time doSomething() takes, plus any time lost in calls or being preempted.

You might want to know the time at the start of the call, and use that to compute the time for the next interval.

Since you want to skip calls that do not fit into the interval, the time until the next call must be a multiple of interval (if the time is just a bit over, you skip until the next interval).

For example (pseudo code):

int callback()
{
    auto now = time_now();
    doSomething();
    auto elapsed_time = time_now() - now;
    auto next_time = interval - (elapsed_time % interval);
    schedule_timer(callback, next_time);
}

Of course, there would still be some overhead. This overhead comes from the time the computation takes, the function call, and any variation introduced by the timer itself.

You can solve that by moving the instructions around:

int callback()
{
    doSomething();
    auto new_now = time_now(); // time is measured around this point
    auto elapsed_time = new_now - now; // now declared outside
    auto next_time = interval - (elapsed_time % interval);
    now = new_now;
    schedule_timer(callback, next_time);
}

Now, you may encapsulate this logic away:

int callback()
{
    doSomething();
    schedule_next(callback);
}

As you have seen, I have said that interval and now are declared outside. In practice you may create a class that is initialized with interval, and takes the initial now value. If this class also takes the callback pointer, it can wrap the call with the necessary code to invoke it at stable intervals, skipping calls if it takes too long.


I see you tagged this with “game-loop”. You can totally use your game loop to schedule calls, what you need is to keep a sorted structure from where you can pull the next timer to go up, and if it has gone up, call it.

Of course, that would be single threaded and would be eating time from your game loop, the calls would NOT run in parallel. If you want calls to run in parallel, you would have to schedule in the timer a call that invokes what you want but to run from a thread pool.

There would be some overhead due to thread pool, but the good thing about this is that you do not have to wait for your invocations to complete because what is scheduled is the call to the thread pool, which returns immediately. Thus you can (if you want) code it to reschedule immediately, or you can push to the thread pool a call that wraps the invocations you want and reschedules at the end, whichever you prefer.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .