8
\$\begingroup\$

I want to have something happen every N seconds, how would I do that? Maybe use a timer but how?

\$\endgroup\$
  • \$\begingroup\$ I've made your question more generic as I think it's more useful to more people this way. \$\endgroup\$ – MichaelHouse Nov 9 '13 at 17:58
  • \$\begingroup\$ Based on the comments on one of the answers, I don't believe the poster is looking for the timer bit, but how to change the sprite frame. That's more dependent on what platform we are talking about. Regardless, now that the question has been edited , it doesn't represent what he's really asking. Java 2D was important to the question he's trying to ask. \$\endgroup\$ – prototypical Nov 11 '13 at 3:38
  • \$\begingroup\$ Changing the sprite and making it happen every 5 seconds are unrelated and should be asked as different questions. Please ask a new question about changing the sprite. Make sure to include what you've tried and what about it isn't working. \$\endgroup\$ – MichaelHouse Nov 11 '13 at 5:30
14
\$\begingroup\$

A common approach for this is to use the update loop and delta time.

float timerCurrent = 0f;
float timerTotal = 5f;


Update() {
    timerCurrent += deltaTime;
    if(timerCurrent >= timerTotal) {
        //do timer action
        timerCurrent -= timerTotal;
    }
}

This supposes that you have access to a deltaTime variable. Delta time is simply the time that's elapsed since the last frame. Many engines will have this available to you, or you can learn more about setting up your own here.

\$\endgroup\$
  • \$\begingroup\$ Is this in any technical sense preferable to starting an explicit timer as in @Josh's answer? \$\endgroup\$ – Jack M Nov 9 '13 at 23:14
  • \$\begingroup\$ @JackM That'll depend on the implementation of the timer. The reason I answered like this is because it's language agnostic and very simple to implement. \$\endgroup\$ – MichaelHouse Nov 10 '13 at 0:30
  • 1
    \$\begingroup\$ @JackM: It's also preferable if you ever run under a debugger. The accumulated game time can stop when you hit a breakpoint rather than having every timer expire and fire instantly on continue. \$\endgroup\$ – Ben Jackson Nov 10 '13 at 1:58
  • \$\begingroup\$ One has to be careful, as the game could freeze for example and ticks could be lost. Therefore one has to invoke the action of a timer for each tick with the specified delta that has passed and not only once etc. \$\endgroup\$ – Christian Ivicevic Nov 11 '13 at 12:07
  • \$\begingroup\$ This method doesn't rely on counting ticks, it relies on delta time. If there is an extra long frame, the delta time is extra long too. However, in many cases it's preferable to limit the delta time, extra long frames can cause issues with physics and such. This method is then superior to just using the current time minus the start time as it will better sync with the other calculations in the game when limiting the span of delta time. \$\endgroup\$ – MichaelHouse Nov 11 '13 at 14:04
3
\$\begingroup\$

In most languages, you need to start the clock with some kind of function call along the lines of clock.startTimer() before you enter the main loop. Then, you have to store the clock time value before you enter the main loop into a variable with a function like time = clock.getTime(). Store your step time into variable n.

In your main loop, the check you want to make is something along the lines of

if(time + n <= clock.getTime())
     //do stuff
     time = clock.getTime() //important to assign new time value here

Note: I'm not sure what language/library you are looking at so this is just a generic algorithm I thought of off the top of my head. It may not suit your needs exactly. Some languages/libraries require you to create a clock object while others you can simply make a function call directly.

As per the comments below, you must be careful with threading issues depending on which language you are using. You also should use a double float to store time.

\$\endgroup\$
  • 1
    \$\begingroup\$ Good answer. This could have threading issues in some languages (eg. .NET) where a timer is implemented in a separate thread from your game loop. \$\endgroup\$ – ashes999 Nov 9 '13 at 20:51
  • 1
    \$\begingroup\$ Also important to note here that if time is going to be storing elapsed game time, it should use a double-precision floating point format. \$\endgroup\$ – kevintodisco Nov 9 '13 at 22:08
  • \$\begingroup\$ These are good points, I'll add them to the answer. \$\endgroup\$ – Josh Nov 9 '13 at 23:10
2
\$\begingroup\$

As other answers already pointed out, implementing a timer can be done by incrementing a stored value by each frame's deltaTime, and comparing it to the expected duration. For completeness, I'll include code which is very similar to the other answers:

float elapsed = 0.0f;
float duration = 4.0f;

void update(float deltaTime) {
    elapsed += deltaTime;
    if (elapsed <= duration) {
        // Run code.
        elapsed = 0.0f;
        // Maybe remove from update loop?
    }
}

How you want to handle the // Run code. portion is up to you. Maybe you have a Timer class, an instance of which takes a delegate (C#) or a callback (C++) and calls it when the timer expires. Also, pausing the timer is a matter of removing it from the update loop.

An alternative approach is to mark the starting time of the timer, and instead do an on-demand calculation of elapsed time:

double startTime = 0.0; // This is a double for a reason, I'll explain below.
bool running = false;

void start() {
    startTime = getTime(); // This is whatever system time call you want to use.
    running = true;
}

double getElapsed() {
    double elapsed = getTime() - startTime;
    return elapsed;
}

This style gives a little more control to the user of the timer. The structure itself isn't concerned with what to do when the elapsed time reaches a certain point; it isn't even updating. The user can simply query the elapsed time when it's needed. This pattern has the unfortunate side-effect of not being debugger-friendly. System time continues on as your program is halted on a debugger, so timers like this will behave differently when stepping through programs. A potential solution to that is to maintain a program-specific elapsed time value which is updated every frame using system time deltas.

I think most important though are two quirks of timing on a computer, especially when it comes to game development. The first is floating point precision and the second is native timer resolution.

You'll note that in the second example, I used a double type instead of a float, as in the first example (the typename of course depends on the language you are using). The reason for this is the second example is storing total elapsed game time. If the game is left running for a very long time, single-precision floating point format values will have insufficient precision to accurately measure elapsed time, leading to stability issues. The first example is fine using the float type so long as huge durations are not expected.

On the other end of the spectrum, if the update time you're expecting is small enough, you may not actually be able to initially achieve it, depending on how you get system time. Timers will often be dependent on the timer resolution of the OS you are running on. For example, the default timer resolution of Windows 7 and below is 15.6 ms. This means that the lowest timer precision you could achieve using functions such as timeGetTime or GetTickCount, is 15.6 ms, unless you change the timer resolution (there are dangers associated with that, too).

Well, that turned out a bit long, but these are important things to be aware of when implementing timers.

\$\endgroup\$
  • \$\begingroup\$ ye thanks but I now how to do that bit but how would I change the sprite back and froward \$\endgroup\$ – user2957632 Nov 10 '13 at 8:16
  • \$\begingroup\$ @user2957632 That is not what your question is asking right now. Please make it more clear. \$\endgroup\$ – kevintodisco Nov 11 '13 at 2:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.