Timers

Timers are not something every game uses so you might be wondering why I’m covering them in this article. Trying to get SDL timers to work caused me a lot of aggravation and I spent hours trying to figure out what the problem was. I’m writing about SDL timers to save you the aggravation I went through.

A timer is a function the operating system calls periodically. You get to specify how often the timer fires, which is how often the operating system calls the timer. Use a timer when you want to do something repeatedly in your program at regular time intervals.

Writing a Timer

A timer function takes the form.

Uint32 TimerFunctionName(Uint32 interval, void* param)

The interval argument specifies the timer’s firing rate in milliseconds. The param argument contains data you can supply to the timer when installing the timer.

C++ programs that want timer functions to be member functions of a class must declare the timer to be a static function in the header file.

static Uint32 TimerFunctionName(Uint32 interval, void* param);

If you read my article on Carbon event timers, you know that timers generally call functions in your program. Unfortunately you cannot directly call a function from a SDL timer. To call a function from a timer, you must create a SDL user event and add the event to the event queue. Your event handler calls the function when the user event occurs.

A SDL user event has four fields you must set.

  • Type, which will be SDL_USEREVENT for a user event.
  • Code, which is an integer value that uniquely defines the event type.
  • Data1 and data2, which let you attach data to the event. If you have no data to attach, set the fields to 0.

Call the function SDL_PushEvent() to add the event you created to the event queue. The following timer function creates an event to run a game loop:

const int RUN_GAME_LOOP = 1;

Uint32 GameApp::GameLoopTimer(Uint32 interval, void* param)
{
    // Create a user event to call the game loop.
    SDL_Event event;
    
    event.type = SDL_USEREVENT;
    event.user.code = RUN_GAME_LOOP;
    event.user.data1 = 0;
    event.user.data2 = 0;
    
    SDL_PushEvent(&event);
    
    return interval;
}

Notice how the timer returns the value of the interval argument. Doing this tells the timer to fire at the same rate next time. If you want the timer to stop firing, return 0.

Installing a Timer

Call the function SDL_AddTimer() to install the timer. This function takes three arguments. The first argument is the firing rate in milliseconds. The second argument is the name of the timer function. The third argument is any data you want to supply to the timer. The following function code installs the timer I wrote in the previous section and tells it to fire 50 times per second:

SDL_TimerID timer;
timer = SDL_AddTimer(20, GameLoopTimer, this);

Next (SDL Event Loop)

Previous (Creating the OpenGL Draw Context)