SDL Sprite Sheet

Opinions on my sprite sheet function

  • (2 Pages)
  • +
  • 1
  • 2

22 Replies - 10376 Views - Last Post: 08 July 2010 - 05:51 AM Rate Topic: -----

#1 ZOMBIE!!!  Icon User is offline

  • D.I.C Head

Reputation: 27
  • View blog
  • Posts: 206
  • Joined: 28-October 09

SDL Sprite Sheet

Posted 28 June 2010 - 06:02 PM

Hey guys, just recently got into SDL and I wanted to make a function to handle sprite sheets. I looked at the Lazy Foo tutorial to get me started. This function isn't quite done yet, but I want some opinions on ways I could improve it.

Here is the function:



http://pastebin.com/AubnfLTJ


I think I am going to pair this with a texturing function like lazyfoo did. But I wanna make sure It looks good before I go any further.


Thanks in advance,

ZOMBIE!!!

Is This A Good Question/Topic? 1
  • +

Replies To: SDL Sprite Sheet

#2 ghillieLEAD  Icon User is offline

  • D.I.C Head

Reputation: 31
  • View blog
  • Posts: 208
  • Joined: 08-March 10

Re: SDL Sprite Sheet

Posted 28 June 2010 - 06:05 PM

The code for the curious...

// Wraps a rectangle around every sprite in a sprite sheet and stores it in an array of rectangles(Clip[])
 
void spriteSheet(string FileName, int SpriteWidth = 64,int SpriteHeight= 64, int SheetDimension = 4){
 
 
    int Sprites = SheetDimension * SheetDimension;// Number of Sprites on sheet
    SDL_Rect Clip[Sprites]; // Rectangles that will wrap around each sprite
 
    int SpriteXNum = 0;// The number sprite going from left to right
    int SpriteYNum = 0;// The number sprite going from top to bottom
    int YIncrement = 0;// Increment for each row.
    for(int i = 0; i< Sprites; i++){// While i is less than number of sprites
 
        if(i = 0){// First sprite starts at 0,0
            Clip[i].x = 0;
            Clip[i].y = 0;
            Clip[i].w = SpriteWidth;
            Clip[i].h = SpriteHeight;
        }
        else{
 
            if(SpriteXNum < SheetDimension - 1 ){// If we have reached the end of the row, go back to the front of the next row
                SpriteXNum = 0;
            }
            if(YIncrement < SheetDimension - 1){
                SpriteYNum += 1;                         // Example of 4X4 Sheet
            }                                            //   ________________
            Clip[i].x = SpriteWidth * SpriteXNum;        //  | 0 | 1 | 2 | 3 |
            Clip[i].y = SpriteHeight * SpriteYNum;       //  |===============|
                                                         //  | 0 | 1 | 2 | 3 |
                                                         //  |===============|
            Clip[i].w = SpriteWidth;                     //  | 0 | 1 | 2 | 3 |
            Clip[i].h = SpriteHeight;                    //  |===============|
                                                         //  | 0 | 1 | 2 | 3 |
        }                                                //  |---------------|
        SpriteXNum++;
        YIncrement++;
    }
 
}


Was This Post Helpful? 0
  • +
  • -

#3 Fib  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 161
  • View blog
  • Posts: 554
  • Joined: 12-March 09

Re: SDL Sprite Sheet

Posted 29 June 2010 - 07:17 AM

Good job ZOMBIE!!!. It looks good so far!

The only thing I can think of to improve it, would be to add that function to a Sprite class.

This post has been edited by Fib: 29 June 2010 - 07:19 AM

Was This Post Helpful? 0
  • +
  • -

#4 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 999
  • View blog
  • Posts: 4,175
  • Joined: 14-February 08

Re: SDL Sprite Sheet

Posted 29 June 2010 - 03:44 PM

Also you may want to look at limiting the speed of the animation, possibly tying it to the frame rate that your sprite moves at.
Was This Post Helpful? 0
  • +
  • -

#5 ZOMBIE!!!  Icon User is offline

  • D.I.C Head

Reputation: 27
  • View blog
  • Posts: 206
  • Joined: 28-October 09

Re: SDL Sprite Sheet

Posted 29 June 2010 - 03:58 PM

Yeah, as I said it's not quite done yet. I will definitely make some sort of sprite class to hold this function.
Was This Post Helpful? 0
  • +
  • -

#6 ZOMBIE!!!  Icon User is offline

  • D.I.C Head

Reputation: 27
  • View blog
  • Posts: 206
  • Joined: 28-October 09

Re: SDL Sprite Sheet

Posted 01 July 2010 - 01:55 AM

Hey again. I have a game that I would be very happy if you participated in. It's called "Find the Bug". I have a new updated version of the function that takes a vector of surfaces and applies each frame of the sprite sheet to an element of that vector. Here's the code:



#include <string>
#include <iostream>
#include <vector>
#include <SDL/SDL.h>
#include <iostream>
using namespace std;

// Wraps a rectangle around every sprite in a sprite sheet and stores it in an array of rectangles(Clip[])

void loadSpriteSheet(string FileName, vector<SDL_Surface*> Frames, int SpriteWidth = 64,int SpriteHeight= 64, int SheetDimension = 4){

    int Sprites = SheetDimension * SheetDimension;// Number of Sprites on sheet
    SDL_Rect Clip[Sprites]; // Rectangles that will wrap around each sprite
    SDL_Surface* SpriteSheet = SDL_LoadBMP(FileName.c_str());

    int SpriteXNum = 0;// The number sprite going from left to right
    int SpriteYNum = 0;// The number sprite going from top to bottom
    int YIncrement = 0;// Increment for each row.
    for(int i = 0; i< Sprites; i++){// While i is less than number of sprites

        if(i = 0){// First sprite starts at 0,0
            Clip[i].x = 0;
            Clip[i].y = 0;
            Clip[i].w = SpriteWidth;
            Clip[i].h = SpriteHeight;
        }
        else{

            if(SpriteXNum < SheetDimension - 1 ){// If we have reached the end of the row, go back to the front of the next row
                SpriteXNum = 0;
            }
            if(YIncrement < SheetDimension - 1){
                SpriteYNum += 1;                         // Example of 4X4 Sheet
            }                                            //   ________________
            Clip[i].x = SpriteWidth * SpriteXNum;        //  | 0 | 1 | 2 | 3 |
            Clip[i].y = SpriteHeight * SpriteYNum;       //  |===============|
                                                         //  | 0 | 1 | 2 | 3 |
                                                         //  |===============|
            Clip[i].w = SpriteWidth;                     //  | 0 | 1 | 2 | 3 |
            Clip[i].h = SpriteHeight;                    //  |===============|
                                                         //  | 0 | 1 | 2 | 3 |
        }                                                //  |---------------|
        SpriteXNum++;
        YIncrement++;
        cout<<"IN LOOP"<<endl;
    }
    SDL_Rect Offset;
    Offset.x = 0;
    Offset.y = 0;
    for(int i = 0; i < Sprites; i++){
        SDL_BlitSurface(SpriteSheet,&Clip[i],Frames[i],&Offset);
    }
    cout<<"BLITTING IN FUNC"<<endl;
}
int main(int args, char* argv[])
{

    if(SDL_Init(SDL_INIT_EVERYTHING) == -1){
        cout<<"Error in initializing"<<endl;
    }
    cout<<"SDL INITIALIZED"<<endl;
    
    
    vector<SDL_Surface*> Frames;
    
    loadSpriteSheet("SpriteSheet.bmp", Frames,32,32,2);
    
    
    SDL_Surface* Screen = NULL;
    Screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
    
    SDL_BlitSurface(Frames[1],NULL,Screen,NULL);
    if(Screen == NULL){
        cout<<"Error in blitting to screen";
    }
    SDL_Delay(2000);
    for(int i = 0;i<Frames.size();i++){
        SDL_FreeSurface(Frames[i]);
    }
    SDL_FreeSurface(Screen);
    SDL_Quit;
    return 0;
}



I'm not getting any errors, but when I run it, nothing happens. I placed a lot of cout<<"in loop" in for loops to make sure I am not in an infinite loop, but nothing shows up. Not even when it should go into the loop.

Thanks for playing the game in advance,

ZOMBIE!!!
Was This Post Helpful? 0
  • +
  • -

#7 Fib  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 161
  • View blog
  • Posts: 554
  • Joined: 12-March 09

Re: SDL Sprite Sheet

Posted 01 July 2010 - 06:23 AM

I'm going to assume you're using windows. If not, then i'm sorry. If you're expecting cout to output to the console, it won't be there. SDL redirets the standard output to 2 text files instead. The 2 text files are stdout.txt, and stderr.txt. If you check the directory that your executable is in while your program is running, you will see the 2 files. Just open up stdout.txt to see everything from cout.

Alternatively, you can include <windows.h> and use the MessageBox() function to help you debug.
MessageBox(NULL, "IN LOOP", "Debugging", MB_OK);


I always use the latter because the pop up message box is a very easy and obvious method.

Also, a few things that i noticed in your code:
1) You included iostream twice
2) You don't need to free your screen surface because SDL_Quit() will do that for you.
3) You should check to see if the screen is NULL after you set the video mode, and before you try to blit to it.
4) Inside of your loadSpriteSheet function at the bottom, you don't need the Offset variable because if you pass NULL as the fourth parameter of SDL_BlitSurface then it will use (0, 0) for the destination position.
5) You don't free your SpriteSheet surface. You should free it at the end of your loadSpriteSheet function.

Now for why it's not working... I would check to see what your SDL_BlitSurface functions return because they may be failing. If SDL_BlitSurface fails it will return -1. Check it in your loadSpriteSheet function and in your main.

I hope that helps you.

This post has been edited by Fib: 01 July 2010 - 07:03 AM

Was This Post Helpful? 1
  • +
  • -

#8 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 999
  • View blog
  • Posts: 4,175
  • Joined: 14-February 08

Re: SDL Sprite Sheet

Posted 01 July 2010 - 08:17 AM

I am having a little trouble understanding exactly what you are trying to do with the vector, you don't actually push anything onto it and then you try to loop through it :s

This kind of thing is much easier to achieve by simply creating a function that only draws a specific part of an image, then you can pass in the needed values. A sprite sheet is just one large image split into smaller images, you can loop through it by knowing the height and width of the images and then drawing only that part, incrementing the height or width each time.

The method you seem to be trying would only really work if you used lots of individual images and then pushed them onto a vector, not very efficient.

Here is an example of a function that draws only part of an image.
bool DrawPartOfImage(SDL_Surface* dest, SDL_Surface* src, int x, int y, int x2, int y2, int width, int height) {
        if(dest == NULL || src == NULL) {
                return false;
        }
        
        SDL_Rect destR;
        
        destR.x = x;
        destR.y = x;
        
        SDL_Rect srcR;
        
        srcR.x = x2;
        srcR.y = y2;
        srcR.w = width;
        srcR.h = height;
        
        SDL_BlitSurface(src, &srcR, dest, &destR);
        
        return true;
}


Was This Post Helpful? 0
  • +
  • -

#9 Fib  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 161
  • View blog
  • Posts: 554
  • Joined: 12-March 09

Re: SDL Sprite Sheet

Posted 01 July 2010 - 02:58 PM

I agree with stayscrisp. The method you are trying to use is not very efficient.
Was This Post Helpful? 0
  • +
  • -

#10 ZOMBIE!!!  Icon User is offline

  • D.I.C Head

Reputation: 27
  • View blog
  • Posts: 206
  • Joined: 28-October 09

Re: SDL Sprite Sheet

Posted 01 July 2010 - 06:28 PM

I am trying to implement staycrisp's idea (loading only one frame) the only difference is that I don't want to have to put in the x and y coordinate of the frame in the sprite sheet. I'm having trouble thinking right now, I'm betting there is a more efficient way to finding what the x and y coordinate are. THis is what I have:


#include <string>
#include <iostream>
#include <vector>
#include <SDL/SDL.h>
#include <iostream>
using namespace std;

// Takes one frame of a sprite sheet (Sheet) and applies it to 
// a frame (Frame)

void loadFrame(SDL_Surface* Sheet, SDL_Surface* Frame, int SpriteWidth, int SpriteHeight, int SheetDimensionX, int SheetDimensionY, int FrameNum){

                    SDL_Rect Clip;
                    Clip.w = SpriteWidth;
                    Clip.h = SpriteHeight;

                    int Row = 1;
                    int Column = 1;

                    for(int i = 1; i <= FrameNum; i++){
                        if(Column > SheetDimensionX){
                            Column = 1;
                        }
                        if(i > SheetDimensionX){
                            Row++;
                            SheetDimensionX *= 2;
                        }
                        if(i == FrameNum){
                            break;
                        }
                        Column++;
                        cout<<"Column: "<<Column<<"/t"<<"Row: "<<Row<<endl;
                    }

                    Clip.x = (Column - 1) * SpriteWidth;
                    Clip.y = (Row - 1) * SpriteHeight;
                                          
                    SDL_Rect Offset;
                    Offset.x = 0;
                    Offset.y = 0;
                        
                    SDL_BlitSurface(Sheet, &Clip, Frame, &Offset);
                
}
                
int main(int args, char* argv[])
{

    SDL_Init(SDL_Init(SDL_INIT_EVERYTHING));




    SDL_Surface* Screen = NULL;
    Screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
    
    SDL_Surface* SpriteSheet = SDL_LoadBMP("SpriteSheet.bmp");
    
    SDL_Surface* Frame = NULL;
    
    loadFrame(SpriteSheet, Frame, 32, 32, 2, 2, 2);
    
    SDL_BlitSurface(Frame,NULL,Screen,NULL);
    
    
    SDL_Delay(2000);
    
    SDL_Quit();
    return 0;
}




I don't know if it works because code::blocks is have issues with plugins. But if you can offer a more efficient way of finding the x and y coordinate of the frame please let me know. Also, one other quick question: Would it be better to run "Frame" as a parameter, or return an SDL_Surface* like Frame = loadFrame(SpriteSheet,32,32,2,2)?


Thanks again,

ZOMBIE!!!
Was This Post Helpful? 0
  • +
  • -

#11 ZOMBIE!!!  Icon User is offline

  • D.I.C Head

Reputation: 27
  • View blog
  • Posts: 206
  • Joined: 28-October 09

Re: SDL Sprite Sheet

Posted 01 July 2010 - 11:54 PM

So I updated it and got it to run. For some reason there is an issue in the blitting of the piece of the sprite sheet to the frame at the end of the function.


#include "SDL/SDL.h"
#include <string>
#include <vector>
#include <iostream>
using namespace std;

// Takes one frame of a sprite sheet (Sheet) and applies it to
// a frame (Frame)

int loadFrame(SDL_Surface* Sheet, SDL_Surface* Frame, int SpriteWidth, int SpriteHeight, int SheetDimensionX, int SheetDimensionY, int FrameNum){
    if(Sheet == NULL){
        cerr<<"SPRITESHEET WAS NULL"<<endl;
        return -1;
    }

    SDL_Rect Clip;
    Clip.w = SpriteWidth;
    Clip.h = SpriteHeight;

    int Row = 1;
    int Column = 1;

    for(int i = 1; i <= FrameNum; i++){
        if(Column > SheetDimensionX){
            Column = 1;
        }
        if(i > SheetDimensionX){
            Row++;
            SheetDimensionX *= 2;
        }
        if(i == FrameNum){
            break;
        }
        Column++;
    }

    cout<<"Column "<<Column<<endl<<"Row "<<Row<<endl;



    Clip.x = (Column - 1) * SpriteWidth;
    Clip.y = (Row - 1) * SpriteHeight;


    cout<<"X "<<Clip.x<<endl<<"Y "<<Clip.y<<endl;
    cout<<"Width "<<Clip.w<<endl<<"Height "<<Clip.h<<endl;


    SDL_BlitSurface(Sheet, &Clip, Frame, NULL);
    if(Frame == NULL){
        cerr<<"FRAME IS NULL AFTER BLITTING"<<endl;
        return -1;
    }

    return 0;
}

int main(int args, char* argv[])
{

    SDL_Init(SDL_Init(SDL_INIT_EVERYTHING));




    SDL_Surface* Screen = NULL;
    Screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);

    SDL_Surface* SpriteSheet = SDL_LoadBMP("SpriteSheet.bmp");
    if(SpriteSheet == NULL){
        return 2;
    }

    SDL_Surface* Frame = NULL;

    if(loadFrame(SpriteSheet, Frame, 32, 32, 2, 2, 3) == -1){
            return -1;
    }


    SDL_BlitSurface(Frame,NULL,Screen,NULL);


    SDL_Delay(2000);

    SDL_Quit();
    return 0;
}




Thanks for any help,
ZOMBIE!!! :dangole:
Was This Post Helpful? 0
  • +
  • -

#12 Fib  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 161
  • View blog
  • Posts: 554
  • Joined: 12-March 09

Re: SDL Sprite Sheet

Posted 02 July 2010 - 06:16 AM

This might be your problem:
SDL_Init(SDL_Init(SDL_INIT_EVERYTHING));


This line is at the top of your main.

It should be:
SDL_Init(SDL_INIT_EVERYTHING);


Also, don't forget to free all of your surfaces. Your not freeing spriteSheet, or Frame. The only surface that you don't have to free is screen because SDL_Quit() does that for you.

I hope that helps.

This post has been edited by Fib: 02 July 2010 - 06:18 AM

Was This Post Helpful? 0
  • +
  • -

#13 ZOMBIE!!!  Icon User is offline

  • D.I.C Head

Reputation: 27
  • View blog
  • Posts: 206
  • Joined: 28-October 09

Re: SDL Sprite Sheet

Posted 03 July 2010 - 06:46 PM

For some reason the SDL_LoadBMP("SpriteSheet.bmp") doesn't work. SpriteSheet.bmp is in the same folder. I even tried to make a project and included this .cpp file and the .bmp, but it didn't work. It could be an issue with my computer considering it Blue Screened a little while ago.

Can anyone find a problem:
#include "SDL/SDL.h"
#include <string>
#include <vector>
#include <iostream>
using namespace std;

// Takes one frame of a sprite sheet (Sheet) and applies it to
// a frame (Frame)

int loadFrame(SDL_Surface* Sheet, SDL_Surface* Frame, int SpriteWidth, int SpriteHeight, int SheetDimensionX, int SheetDimensionY, int FrameNum){
    cout<<endl<<endl<<"In loadFrame():"<<endl;
    if(Sheet == NULL){
        cerr<<"Sprite Sheet was NULL"<<endl;
        return -1;
    }

    SDL_Rect Clip;
    Clip.w = SpriteWidth;
    Clip.h = SpriteHeight;

    int Row = 1;
    int Column = 1;

    for(int i = 1; i <= FrameNum; i++){
        if(Column > SheetDimensionX){
            Column = 1;
        }
        if(i > SheetDimensionX){
            Row++;
            SheetDimensionX *= 2;
        }
        if(i == FrameNum){
            break;
        }
        Column++;
    }

    Clip.x = (Column - 1) * SpriteWidth;
    Clip.y = (Row - 1) * SpriteHeight;

    cout<<"Blitting Sheet to Frame"<<endl;
    SDL_BlitSurface(Sheet, &Clip, Frame, NULL);
    if(Frame == NULL){
        cerr<<"Error in Blitting"<<endl;
        SDL_FreeSurface(Sheet);
        return -1;
    }

    SDL_FreeSurface(Sheet);
    cout<<"End of loadSheet()"<<endl;
    return 0;
}

int main(int args, char* argv[])
{
    cout<<"Initializing SDL..."<<endl;
    if(SDL_Init(SDL_INIT_EVERYTHING)== -1){
        cerr<<"ERROR IN INITIALIZING SDL"<<endl;
        return -1;
    }




    SDL_Surface* Screen = NULL;

    Screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);

    SDL_Surface* SpriteSheet = NULL;
    cout<<"Loading SpriteSheet.bmp..."<<endl;
    SpriteSheet = SDL_LoadBMP("SpriteSheet.bmp");
    if( SpriteSheet == NULL){
        cerr<<"ERROR IN LOADING SPRITESHEET.BMP"<<endl;
        return -1;
    }

    SDL_Surface* Frame = NULL;
    cout<<"Using loadFrame function..."<<endl;
    if(loadFrame(SpriteSheet, Frame, 32, 32, 6, 4, 3) == -1){
            cerr<<"loadFrame RETURNED -1"<<endl;
            return -1;
    }

    cout<<"Blitting Frame to Screen..."<<endl;
    SDL_BlitSurface(Frame,NULL,Screen,NULL);


    SDL_Delay(2000);
    cout<<endl<<endl<<"Quitting SDL..."<<endl;
    SDL_Quit();
    return 0;
}


Was This Post Helpful? 0
  • +
  • -

#14 Fib  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 161
  • View blog
  • Posts: 554
  • Joined: 12-March 09

Re: SDL Sprite Sheet

Posted 06 July 2010 - 06:22 AM

Try giving the complete path to your SpriteSheet.bmp and see if that works.

For example:
SpriteSheet = SDL_LoadBMP("c:\\game\\graphics\\SpriteSheet.bmp");


Just replace the string with the path to your SpriteSheet.bmp. Don't forget to use the double slashes (\\) in your path.

If that doesn't work... well then I don't know.

This post has been edited by Fib: 06 July 2010 - 06:22 AM

Was This Post Helpful? 0
  • +
  • -

#15 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 999
  • View blog
  • Posts: 4,175
  • Joined: 14-February 08

Re: SDL Sprite Sheet

Posted 06 July 2010 - 07:29 AM

The problem is still in your loadFrame function, instead of returning -1 for everything you should return a message so you can see where the problem is. I still don't understand the approach you are taking, can you explain the logic behind your load frame function?

The way I described would not need to know the x and y coordinates of the sprite sheet frame, it only needs to know the height and width of each part of the sprite sheet. You could then pass the maximum number of frames and the row or column you want to loop through.

pseudo code
Walk Button Pressed ()
{
    Player->Animate(8,1); // the walk loop has 8 frames and is in the first column of the sprite sheet
}

Attack Button Pressed ()
{
    Player->Animate(3,2); // the attack loop has 3 frames and is in the second column of the sprite sheet
}



This is what you might want to achieve. I can give you a few more pointers if you need them but I would have a good rethink about your load frame function and try to logically step through it, as it seems to be messing with your code.

This post has been edited by stayscrisp: 06 July 2010 - 07:29 AM

Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2