SDL Tutorial Series - Part 5 - Dealing with Time


Timing information is essential for video game programming. The programmer must keep track of how much time has elapsed since the last frame for the video game simulation to run properly. Timing must be used to properly run animations, run physics for game objects, and trigger events such as a scripted sequence. Your games will need to access timing information and this tutorial will show you how by using the SDL.

There are only four functions in the SDL that relate to time. The one that we are most interested in is this one:
Uint32 SDL_GetTicks(void)
This function will return the number of milliseconds that have elapsed since the SDL was initialized. A millisecond is defined as a thousandth (1/1000) of a second. This will provide us with enough accuracy for use in games. At first glance this does not seem all that useful but you will soon see how great this function is.

We will be adding onto the code from the previous tutorial. If you have not done so already, open the code in your compiler and we will begin.

First, find this line:
// Main loop
SDL_Event event;

After it add the following:
// Image motion variables
float x = 0.1f, y = 0.1f;
float xVel = 50.0f, yVel = 40.0f;

// Timing variables
Uint32 old_time, current_time;
float ftime;

// Need to initialize this here for event loop to work
current_time = SDL_GetTicks();

Change the while loop to this:
while(1)
{
   // Update the timing information
   old_time = current_time;
   current_time = SDL_GetTicks();
   ftime = (current_time - old_time) / 1000.0f;

   // Check for messages
   if (SDL_PollEvent(&event))
   {
      // Check for the quit message
      if (event.type == SDL_QUIT)
      {
         // Quit the program
         break;
      }
   }
   // Update the image position
   x += (xVel * ftime);
   y += (yVel * ftime);

   // Check boundaries
   if (x <= 0.0f)
      xVel *= -1.0f;
   if (x >= (display->w - image->w))
      xVel *= -1.0f;
   if (y <= 0.0f)
      yVel *= -1.0f;
   if (y >= (display->h - image->h))
      yVel *= -1.0f;

   // Clear the screen
   if (SDL_FillRect(display, NULL, SDL_MapRGB( display->format, 0,0,0)) != 0)
   {
      cerr << "SDL_FillRect() Failed: " << SDL_GetError() << endl;
      break;
   }

   SDL_Rect dest;
   dest.x = static_cast<int>(x);
   dest.y = static_cast<int>(y);

   // Apply the logo to the display
   if (SDL_BlitSurface(image, NULL, display, &dest) != 0)
   {
      cerr << "SDL_BlitSurface() Failed: " << SDL_GetError() << endl;
      break;
   }

   //Update the display
   SDL_Flip(display);
}

Alright, that is it. Be sure to save your progress. You should now be able to compile and run the program. Select 'Build' from the menu bar and click on 'Build Solution'. There should not be any errors or warnings. Now, select 'Debug' from the menu bar and click on 'Start Without Debugging'. You should see the image we used from the previous tutorial moving around the screen and bouncing off the sides. Now that you have seen the program in action, lets examine how it works.

Notice we used three variables to hold timing information: old_time, current_time, and ftime. The old_time and current_time variables are both 32 bit unsigned integers while the ftime variable is a floating point decimal number. Every time we begin the while loop, we record the number of ticks that have elapsed since the SDL was initialized in the current_time variable. We save the old value of current_time in the old_time variable. This is done in order to measure the amount of ticks it took us to complete the previous frame (the one currently being displayed). We take the difference of current_time and old_time, then divide by 1000 to calculate the delta time, which is stored in the variable ftime. If you have taken a physics class you should be familiar with delta time. Remember, there are 1000 ticks per second. If the difference between current_time and old_time was 500 ticks and we divide by 1000, the result would be 0.5 or 1/2 of a second. As you can see, by using SDL_GetTicks() we have a way of measuring the amount of ticks that has elapsed since the last frame and can convert that value to a decimal value.

The motion of the image is controlled by taking the velocity and multiplying it by ftime, then adding it to the position. This is called Frame Rate Independent Movement because no matter how long it takes in between frames, the object moves correctly. The velocity is specified in screen pixels and here the x velocity is 50 pixels a second and the y velocity is 40 pixels a second. If it took 1/10 of a second to render the previous frame then 50 * (1/10) would be 5 pixels in the x direction and 4 pixels in the y direction (40 * 1/10). It is important to note here that the SDL places the origin (0, 0) at the upper left-hand corner of the window. So an increase in x position moves the image to the right and an increase in y moves the image down.

If we let the image move in the same direction without changing its course, it would move off screen. To prevent this, we use 4 if statements to check that it stays inside the window. Remember, SDL measures screen space from the upper left so we have to subtract the width in order to see if the image went too far to the right. It is the same for the y direction.

You will notice that we added this function before we blit the image to the screen.
int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
This function clears every pixel on the screen to the color specified (pure black in our case). Here we use another function, SDL_MapRGB(), to generate the color for us. SDL_MapRGB() will generate a color that is in the same format as our screen so when we call SDL_FillRect(), it should be really fast (in theory). The reason we call this function is to clear the last frame we drew into this buffer. The screen buffer is really just an array of memory and this buffer holds the values we previously copied into it. We need to erase these values and this is how we do it. We set every value in this array to black. Try commenting out this function and then recompile your program to see what happens.

One more item to mention and then we are done. We modified the fourth parameter in SDL_BlitSurface() to use the SDL_Rect structure specified. This allows us to specify where we want to blit the image (in screen coordinates). Here, we cast the x and y position from float to int in order to properly specify the screen coordinates.

This is the end of this tutorial. You have learned how to use SDL_GetTicks() to get timing information from the system to use in your video games. Getting objects to move properly is essential to programming video games and you can now say with pride that you know how to do that. I encourage you to play around a little with this tutorial. Try changing the x and y velocity variables to see how it affects the movement of the image. Also, try clearing the screen to different background colors.

Back to SDL Tutorial Index

Back to Main Page