In the previous SDL tutorial, I showed you how to read from the keyboard and make something move around on the screen. Unfortunately, the movement was not very convincing. Since there was no animation the sprite just slid around the screen. We can do much better than that.

This program builds on the example from the previous tutorial, so if you haven't read it yet, or if you're not clear on the basics of SDL, now's a good time to go check it out.

The Animated Sprite Program

There are only two big changes between this program and the previous sample.

First, I've added a new function called HandleEvents to handle SDL events. In the previous program I used SDL_GetKeyState to get an array of keys being pressed during each iteration of the game loop. For this program I decided to simply move the sprite in response to keyboard events. Be sure to also call SDL_EnableKeyRepeat while initializing SDL to make key events repeat at the specified times.

The other change is the addition of a source rect to SDL_BlitSurface when we're drawing the sprite. The destination rect tells the function where to draw the image on the screen, the source rect tells it which part of the image to use. The sprite image looks like this:

Note that all eight frames of the animation are in one file. The first two frames are moving up, then right, down, and left. As the player moves around the screen we'll toggle between the two frames that represent the direction of movement. This is accomplished by changing the x member of rcSrc in the keyboard handler. For example, while moving up the x value will go back and forth between 0 and 32 in order to switch between the two frames.

The rest of the program is almost exactly the same as the moving sprite program in the previous tutorial.

Save this file as sdlanim.cpp, or sdlanim.c if you'd like to use straight C instead of C++. You'll also need the bitmap files that go with this program. They're available for download with the source code at the bottom of this page.

#include "SDL.h"

#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define SPRITE_SIZE    32

int gameover;

/* source and destination rectangles */
SDL_Rect rcSrc, rcSprite;

void HandleEvent(SDL_Event event)
{
  switch (event.type) {
    /* close button clicked */
    case SDL_QUIT:
      gameover = 1;
      break;

    /* handle the keyboard */
    case SDL_KEYDOWN:
      switch (event.key.keysym.sym) {
        case SDLK_ESCAPE:
        case SDLK_q:
          gameover = 1;
          break;
        case SDLK_LEFT:
          if ( rcSrc.x == 192 )
            rcSrc.x = 224;
          else
            rcSrc.x = 192;
          rcSprite.x -= 5;
          break;
        case SDLK_RIGHT:
          if ( rcSrc.x == 64 )
            rcSrc.x = 96;
          else
            rcSrc.x = 64;
          rcSprite.x += 5;
          break;
        case SDLK_UP:
          if ( rcSrc.x == 0 )
            rcSrc.x = 32;
          else
            rcSrc.x = 0;
          rcSprite.y -= 5;
          break;
        case SDLK_DOWN:
          if ( rcSrc.x == 128 )
            rcSrc.x = 160;
          else
            rcSrc.x = 128;
          rcSprite.y += 5;
          break;
      }
      break;
  }
}

int main ( int argc, char *argv[] )
{
  SDL_Surface *screen, *temp, *sprite, *grass;
  SDL_Rect rcGrass;
  int colorkey;

  /* initialize SDL */
  SDL_Init(SDL_INIT_VIDEO);

  /* set the title bar */
  SDL_WM_SetCaption("SDL Animation", "SDL Animation");

  /* create window */
  screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);

  /* set keyboard repeat */
  SDL_EnableKeyRepeat(70, 70);

  /* load sprite */
  temp   = SDL_LoadBMP("sprite.bmp");
  sprite = SDL_DisplayFormat(temp);
  SDL_FreeSurface(temp);

  /* setup sprite colorkey and turn on RLE */
  colorkey = SDL_MapRGB(screen->format, 255, 0, 255);
  SDL_SetColorKey(sprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, colorkey);

  /* load grass */
  temp  = SDL_LoadBMP("grass.bmp");
  grass = SDL_DisplayFormat(temp);
  SDL_FreeSurface(temp);

  /* set sprite position */
  rcSprite.x = 150;
  rcSprite.y = 150;

  /* set animation frame */
  rcSrc.x = 128;
  rcSrc.y = 0;
  rcSrc.w = SPRITE_SIZE;
  rcSrc.h = SPRITE_SIZE;

  gameover = 0;

  /* message pump */
  while (!gameover)
  {
    SDL_Event event;

    /* look for an event */
    if (SDL_PollEvent(&event)) {
      HandleEvent(event);
    }

    /* collide with edges of screen */
    if ( rcSprite.x < 0 ) {
      rcSprite.x = 0;
    }
    else if ( rcSprite.x > SCREEN_WIDTH-SPRITE_SIZE ) {
      rcSprite.x = SCREEN_WIDTH-SPRITE_SIZE;
    }
    if ( rcSprite.y < 0 ) {
      rcSprite.y = 0;
    }
    else if ( rcSprite.y > SCREEN_HEIGHT-SPRITE_SIZE ) {
      rcSprite.y = SCREEN_HEIGHT-SPRITE_SIZE;
    }

    /* draw the grass */
    for (int x = 0; x < SCREEN_WIDTH / SPRITE_SIZE; x++) {
      for (int y = 0; y < SCREEN_HEIGHT / SPRITE_SIZE; y++) {
        rcGrass.x = x * SPRITE_SIZE;
        rcGrass.y = y * SPRITE_SIZE;
        SDL_BlitSurface(grass, NULL, screen, &rcGrass);
      }
    }
    /* draw the sprite */
    SDL_BlitSurface(sprite, &rcSrc, screen, &rcSprite);

    /* update the screen */
    SDL_UpdateRect(screen, 0, 0, 0, 0);
  }

  /* clean up */
  SDL_FreeSurface(sprite);
  SDL_FreeSurface(grass);
  SDL_Quit();

  return 0;
}

Note, there is no error checking in this program. If something fails, it will be hard to track down. I left out the error checking just to make the program shorter and easier to follow. In a real program you should check the return values of all the SDL function calls.

Compiling

On Linux you can compile this program by typing this command:

g++ sdlanim.cpp `sdl-config --cflags --libs` -o sdlanim

Then run the program by typing:

./sdlanim

If everything worked correctly, a 640x480 window should open with a field of grass and an animated sprite that you can move with the keyboard.

In Visual C++ you'll need to follow these steps:

  1. Create a new empty Windows Application Project.
  2. Add the "sdlanim.cpp" file to your project.
  3. On the menu click Project, then Properties.
  4. Double-click "Configuration Properties".
  5. Double-click "C/C++".
  6. Click "Code Generation".
  7. Change "Runtime Library" to "Multi-threaded DLL".
  8. Double-click "Linker".
  9. Click "Input".
  10. Beside "Additional Dependencies", type "sdl.lib sdlmain.lib".

At this point, you should be able to press F7 to Build the program.

Before we can run the program, you'll need to put the "SDL.dll" file where Windows can find it. Copy the file from "C:\Program Files\SDL-1.2.9" to your new Visual C++ project's folder. If your program compiled without errors, you can now press F5 to execute the program.

Downloads

  • sdlanim.zip - Tutorial Source, Graphics, and Project files for Visual C++ 2005.
  • sdlanim.tar.gz - Tutorial Source, Graphics, and Makefile for Linux.

Resources

Game Programming in C++ is a fairly new book that's getting good reviews. The examples in this book use SDL and OpenGL. There's only one book that I know of that just talks about SDL, Focus on SDL. The book that taught me the most about SDL is actually Programming Linux Games. This book is not just for Linux geeks, most of the information here can be applied to other platforms as well.

This is the next step in learning SDL. You should now be able to create simple games with moving sprites. Feel free to contact me if you have a suggestion about what I should cover next. I'm open for ideas.