Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

SDL Tutorial Series - Part 8 - Simple Keyboard Input using SDL Continued


The last tutorial showed you how to get keyboard input from the player using a technique called polling. As promised, this tutorial will show you how to get input from the player using the event-driven approach. Polling works pretty good if we only need to check a few keys each frame. But what if we had to check for a lot of keys? We would have a lot of if statements in our input logic. The SDL offers an easy way for us to use the event-driven approach in our video games.

We will be modifying the last tutorial so open it up in your compiler. Scroll down to this section of the code.
// Gain access to keystate array
Uint8 *keys = SDL_GetKeyState(NULL);

Remove those two lines and add this:
// Movement variable;
bool move_left = false;
bool move_right = false;
bool move_up = false;
bool move_down = false;

Now, scroll down to the main loop and find these lines:
// Check for messages
if (SDL_PollEvent(&event))
{

Add the following after the curly brace:
// Check for keys
if (event.type == SDL_KEYDOWN)
{
   SDLKey key = event.key.keysym.sym;
   if (key == SDLK_LEFT)
      move_left = true;
   if (key == SDLK_RIGHT)
      move_right = true;
   if (key == SDLK_UP)
      move_up = true;
   if (key == SDLK_DOWN)
      move_down = true;
}
if (event.type == SDL_KEYUP)
{
   SDLKey key = event.key.keysym.sym;
   if (key == SDLK_LEFT)
      move_left = false;
   if (key == SDLK_RIGHT)
      move_right = false;
   if (key == SDLK_UP)
      move_up = false;
   if (key == SDLK_DOWN)
      move_down = false;
}

One more modification and we are done. Scroll down and find this block of code:
// Handle input
if (keys[SDLK_LEFT])
   x -= MOVE_SPEED * ftime;
if (keys[SDLK_RIGHT])
   x += MOVE_SPEED * ftime;
if (keys[SDLK_DOWN])
   y += MOVE_SPEED * ftime;
if (keys[SDLK_UP])
   y -= MOVE_SPEED * ftime;

Change it to this:
// Handle input
if (move_left)
   x -= MOVE_SPEED * ftime;
if (move_right)
   x += MOVE_SPEED * ftime;
if (move_down)
   y += MOVE_SPEED * ftime;
if (move_up)
   y -= MOVE_SPEED * ftime;

Alright, that is it. You should be able to compile and run the program. You will notice that the program behaves exactly like it did before. You might be wondering why we used more lines of code to do the same thing. The answer to that question is to show a different technique for input. Lets say our video game displays a menu when the player presses the F10 button. In the previous tutorial, we would have to check every frame if the F10 button was being pressed. Now, we could just add a check in the event structure to display the menu when the key gets pressed. This is better because we respond to an action taking place instead of checking for an action every frame.

Another note of importance is we are using the same SDLKey definitions as before. This shows the versatility of the SDL library. In the next tutorial you will see how to get mouse input into your game by using the SDL.


See Also:


Back to SDL Tutorial Index

Back to Main Page

SDL Tutorial Series - Part 7 - Simple Keyboard Input using SDL


Every video game needs to get input from the player in order to respond to his or her actions. Without input, there would be no interaction with the user and it would not be a game. This tutorial will teach you a simple method for getting keyboard input from the player by using the SDL library.


We are going to use a technique called polling instead of the event-driven approach. Think of polling like taking a survey. Every frame of our game simulation, we survey which keys are being pressed at that particular time. This is the simplest way to get keyboard input into our application. SDL provides us with a very nice function for this. Here it is:

Uint8 *SDL_GetKeyState(int *numkeys);

This function returns a pointer to an array that holds the state of every key on the keyboard. If a key is being pressed, its value will be one and if not its value will be 0. SDL defines constants to access this array. For example, the space key is defined as SDLK_SPACE. A full list of these constants can be found here. Lets look at the code for this tutorial to see how this all works. I am going to assume at this point that you know how to set up an SDL project in your compiler/platform.

#include <iostream>
#include <SDL.h>

#define MOVE_SPEED 100.0f

using std::cerr;
using std::endl;

int main(int argc, char* args[])
{
   // Initialize the SDL
   if (SDL_Init(SDL_INIT_VIDEO) != 0)
   {
      cerr << "SDL_Init() Failed: " <<
      SDL_GetError() << endl;
      exit(1);
   }

   // Set the video mode
   SDL_Surface* display;
   display = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
   if (display == NULL)
   {
      cerr << "SDL_SetVideoMode() Failed: " <<        
      SDL_GetError() << endl;
      exit(1);
   }

   // Set the title bar
   SDL_WM_SetCaption("SDL Tutorial", "SDL Tutorial");

   // Gain access to keystate array
   Uint8 *keys = SDL_GetKeyState(NULL);

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

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

   // Box
   float x = 35.0f, y = 35.0f;
   SDL_Rect rect;
   rect.h = 30;
   rect.w = 30;

   // Main loop
   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;
         }
      }

      // Handle input
       if (keys[SDLK_LEFT])
         x -= MOVE_SPEED * ftime;
       if (keys[SDLK_RIGHT])
         x += MOVE_SPEED * ftime;
       if (keys[SDLK_DOWN])
         y += MOVE_SPEED * ftime;
       if (keys[SDLK_UP])
         y -= MOVE_SPEED * ftime;

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

      // Draw box
      rect.x = static_cast<int>(x);
      rect.y = static_cast<int>(y);
      if (SDL_FillRect(display, 
                       &rect,
                       SDL_MapRGB(display->format, 255,255,255))
                       != 0)
      {
         cerr << "SDL_FillRect() Failed: " << SDL_GetError() << endl;
         break;
      }
        //Update the display
      SDL_Flip(display);

   }

   // Tell the SDL to clean up and shut down
   SDL_Quit();
    
   return 0;    
}

After you have copied the source code into your program be sure to save your progress. Go ahead and compile and run the program. You should see a white box on the screen. Press the arrow keys on your keyboard to move this box around. As you can see, it is incredibly easy to get keyboard input into your program by using the SDL. In the next tutorial, you will see how to get keyboard input using the event-driven approach.


See Also:


Back to SDL Tutorial Index

Back to Main Page

SDL Tutorial Series - Part 6 - Displaying Text with SDL_ttf


This tutorial will show you how to display text in your SDL applications. Almost every video game needs to display text to the player at some point. We will be using the SDL_ttf library because the standard SDL library does not contain the ability to draw text directly. In order to do this you will have to download and install the SDL_ttf library here. If you are developing on Windows, click on the link labeled 'SDL_ttf-devel-2.0.9-VC8.zip'.

We need to setup the SDL_ttf library so extract the contents of the zip file. Inside the folder there should be a 'include' and 'lib' folder. Copy the SDL_ttf.h header file to the same folder you put SDL.h in tutorial 2. Now, go to the lib folder and copy SDL_ttf.lib to the same folder you placed SDL.lib and SDLmain.lib. Since we already set Visual C++ to include these folders it makes sense to place these files with the main SDL library files.

Create a new project in Visual C++ just like you did in tutorial 3. After you have created your project and have a blank 'Main.cpp' file copy this code.

#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>

using std::cerr;
using std::endl;

int main(int argc, char* args[])
{
   // Initialize the SDL
   if (SDL_Init(SDL_INIT_VIDEO) != 0)
   {
      cerr << "SDL_Init() Failed: " <<
      SDL_GetError() << endl;
      exit(1);
   }

   // Set the video mode
   SDL_Surface* display;
   display = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
   if (display == NULL)
   {
      cerr << "SDL_SetVideoMode() Failed: " <<        
      SDL_GetError() << endl;
      exit(1);
   }

   // Set the title bar
   SDL_WM_SetCaption("SDL Tutorial", "SDL Tutorial");

   // Initialize SDL_ttf library
   if (TTF_Init() != 0)
   {
      cerr << "TTF_Init() Failed: " << TTF_GetError() << endl;
      SDL_Quit();
      exit(1);
   }

   // Load a font
   TTF_Font *font;
   font = TTF_OpenFont("FreeSans.ttf", 24);
   if (font == NULL)
   {
      cerr << "TTF_OpenFont() Failed: " << TTF_GetError() << endl;
      TTF_Quit();
      SDL_Quit();
      exit(1);
   }

   // Write text to surface
   SDL_Surface *text;
   SDL_Color text_color = {255, 255, 255};
   text = TTF_RenderText_Solid(font,
   "A journey of a thousand miles begins with a single step.",
   text_color);

   if (text == NULL)
   {
      cerr << "TTF_RenderText_Solid() Failed: " << TTF_GetError() << endl;
      TTF_Quit();
      SDL_Quit();
      exit(1);
   }

   // Main loop
   SDL_Event event;
   while(1)
   {
      // Check for messages
      if (SDL_PollEvent(&event))
      {
         // Check for the quit message
         if (event.type == SDL_QUIT)
         {
            // Quit the program
            break;
         }
      }

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

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

        //Update the display
      SDL_Flip(display);

   }

   // Shutdown the TTF library
   TTF_Quit();

   // Tell the SDL to clean up and shut down
   SDL_Quit();
    
   return 0;    
}

There are a couple of steps left before we can run this program. First, we need to download some true type fonts. Go here and scroll all the way to the bottom. Download the file 'freefont-ttf.zip', it should be the second one up from the bottom. Extract the contents of this file and copy 'FreeSans.ttf' inside your project folder to where your source code is. This is very important! I named my file 'Main.cpp' and the 'FreeSans.ttf' file is in the same folder. I named my project 'SDLTutorial6' so folder structure looks like this:

SDLTutorial6\SDLTutorial6

You will also need to copy SDL.dll, SDL_ttf.dll, libfreetype-6.dll, and zlib1.dll to the same folder as your exe file. My exe file is in the SDLTutorial6\Debug folder since I am building a debug version. Yours should be in the same.

The last step is to tell the linker to include the SDL.lib, SDLmain.lib and SDL_ttf.lib files. We did this in tutorial 3 so if you need to, refer back to that tutorial. Also, set your project to use the 'Multi-threaded DLL (/MD)' like we did before.

You are now ready to compile and run your program. If all went well you should see the following:

Photobucket


Lets look at the new functions we used in this tutorial.
int TTF_Init()

We have to initialize the TTF library just like the SDL. If there were no errors, 0 is returned and we can use the library. We also have to shut down the library with this function.
void TTF_Quit()
Error information can be obtained by calling this function.
char *TTF_GetError()
This behaves just like SDL_GetError(). The SDL_ttf library is meant to be an extension of SDL and is designed in a similar manner.

The next two functions are the heart of this tutorial.
TTF_Font *TTF_OpenFont(const char *file, int ptsize)
This function opens a true type font file specified by the first parameter in the size specified by the second parameter. It returns a pointer to a TTF_Font structure which can be used for rendering text to SDL_Surfaces by the rendering functions. The rendering function we use in this tutorial is this one.
SDL_Surface *TTF_RenderText_Solid(TTF_Font *font, const char *text, SDL_Color fg)
This function renders the text specified by the second parameter by using the font we previously loaded. It can be rendered in any color specified by the third parameter. It renders the text to an SDL_Surface structure which can then be blitted to the screen. What is nice about this is that we do not have to do this every frame as long as the text remains the same. You will notice in the code that we create the SDL_Surface before the loop. In the loop, we just blit the surface to the screen and do not have to render the text again.

That is it for this tutorial. I encourage you to experiment with this tutorial and play around with the code. Try changing the text, font, color, etc. I find it is best to learn through experimentation. The SDL_ttf library is a nice extension for the SDL library and is a simple way to get text rendered on the screen.


See Also:


Back to SDL Tutorial Index

Back to Main Page

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