SDL: Trying to animate a sprite from a sprite-sheet

Started by
3 comments, last by CrimsonMemory 17 years, 10 months ago
I had gone over the Lesson 3 of the Cone3d tutorial, which is Sprites, but thought it was unwieldy to actually have an entire image file per frame of an animation. So, I made a sprite-sheet, so I could hopefully get each frame surface of the sprite to point to a part of the sprite-sheet. However, I'm kind of clueless as to how to blit a rectangle from the sprite-sheet onto a surface that ISN'T the screen! I tried what seemed logical to me:


   //This right here loads the entire spritesheet into an SDL_Surface temp.
   if ((temp = IMG_Load(fileName.c_str())) == NULL)
   {
       cout << "Error:  could not load image." << endl;
       return;
   }

   //Setting the transparency of the sprite-sheet    
   if (r >= 0)
        SDL_SetColorKey(temp, SDL_SRCCOLORKEY, SDL_MapRGB(temp->format, r, g, b));

    //variables needed to keep track of what part of the sheet
    //I'm blitting.
    int xPos = 0, yPos = 0;
    SDL_Rect src;
    src.w = width;
    src.h = height;
    
    //The sheet is horizontal, and there is only one row, so y will always
    //be zero
    src.y = 0;
    
    //animation is a pointer to struct SpriteFrame, which is simply an
    //SDL_Surface, and here I am creating as many SpriteFrames as
    //there are frames in the animation.
    animation = new SpriteFrame[numFrames];

    for (int i = 0; i < numFrames; i++)
    {
        src.x = xPos;

        //THIS IS PROBABLY THE PART I HAVE WRONG!
        //Unless I somehow got this part right, in which case
        //There's another problem entirely.
        SDL_BlitSurface(temp, &src, animation.image, NULL);

        xPos += width;     //Set xPos to next frame in spritesheet
    }

    SDL_FreeSurface(temp);


Help would be greatly appreciated. Thanks in advance, everyone! Oh, and my error is that absolutely nothing's showing when I choose to draw the sprite to the screen. One more thing: please say something if you think I should post more of my code to figure out my problem! [Edited by - CrimsonMemory on June 8, 2006 3:23:01 PM]
I jumped in a river and what did I see? Black-eyed angels swam with me.- Thom Yorke
Advertisement
animation = new SpriteFrame[numFrames];

Have you created an empty surface to blit to? You need to use SDL_CreateRGBSurface(...) to create a surface of the correct size and format. Theres a good example in the SDL docs.
The Cone3D tutorials, in my opinion, miss out on so much of teaching you what the actual functions do and what you can do with them. They skip over key parts of what you're trying to learn and use horrible methods (eg. one image per frame for an animation).

If you take a look at the SDL_BlitSurface documentation, you'll notice that the second parameter is an SDL_Rect. That is where you want to specify your single frame in the animation.
int SDL_BlitSurface  (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);
Another this is that you don't want to loop through and draw each frame at once. You want to wait a while before moving onto drawing the next frame. My suggestion, would be to implement your own Sprite class which will hold:
  • TileWidth and TileHeight: The width and height of a single tile in your animation
  • FrameNumber: The current frame in the animation to be rendered
  • AnimationSpeed: How fast the animation is to go through each frame

Once you have those, you can do something like this:

class Sprite{    public void Draw(*SDL_Surface destination)    {        // Draw the sprite        SDL_Rect src;        src.x = (int)FrameNumber * TileWidth;        src.w = TileWidth;        src.h = TileHeight;        SDL_BlitSurface(surface, &src, destination, &destRect);                // Advance the animation        FrameNumber += AnimationSpeed;        if(FrameNumber > surface->width)            FrameNumber = 0;    }    /* Other properties and functions here */}

Of course, this is only a demonstration and is horrible pseudocode. Whenever you want to draw your sprite, you'd just call Draw(screen) and the sprite object will manage the animation details for you. Using object orientation will greatly ease your suffering and help you get away from the horrible Cone2D tutorials.
Rob Loach [Website] [Projects] [Contact]
I do have a tutorial that animated a sprite sheet.
</obligatory spamming>

Learn to make games with my SDL 2 Tutorials

Ah, Andrew, thanks SO much for that, that fixed it perfectly! It makes sense, the whole creating a workable surface thing...

Oh, and to Rob, I know what BlitSurface does and all that, I know about the SDL_Rects, and about the pause between the animations. The code I posted was actually part of a SpriteBase class, which was in turn used by a Sprite class which actually handled the drawing and animating and such. The SpriteBase did nothing but hold all the different images in surfaces, so that Sprite objects can point to the sprite base instead of having a separate set of surfaces for each sprite onscreen.

...I have a feeling none of that made ANY sense.
I jumped in a river and what did I see? Black-eyed angels swam with me.- Thom Yorke

This topic is closed to new replies.

Advertisement