SDL Sprite Class Problem

Started by
10 comments, last by Dave Hunt 18 years, 8 months ago
I just keep running into problems... Anyway, the class I created to load and draw sprites in my program (using SDL) isn't working! I create a sprite object and I can display it just fine. I can set a transparent color, and animate images using a strip. Here's the problem: if I ever create more than one sprite object, the program crashes! Actually, if I create another empty sprite object (default constructor with no arguments), then the program runs, but it doesn't exit properly; it crashes! Another thing I realized is that, for some reason, if my destructor isn't declared virtual, then I can't create any sprite objects without the program immediately crashing! Please help! Here's the code for the class. (I hope I post the code correctly. :-P ) SPRITE.H
#ifndef SPRITE_H
#define SPRITE_H

#include<SDL/SDL.h>

#define UINT unsigned short int

class sprite
{
    protected:
        SDL_Surface*  m_psfImage;    //image surface
        SDL_Color     m_cColorKey;   //transparent color key
        Uint8         m_cAlpha;      //alpha channel
        SDL_Rect      m_rBndBox;     //sprite bounding box
        UINT          m_iNumFrms;    //number of frames in the image
        UINT          m_iFrmWidth;   //width of each frame
        UINT          m_iCurrentFrm; //the current frame to display
        
        void LoadFile( char* szFName );
        void ApplyColorKey( SDL_Color cCol );
        void ApplyAlpha( Uint8 iA );
    public:
                 sprite();
                 sprite( char* szFName );
                 sprite( char* szFName, UINT iNFrms, UINT iFrmW);
                 //sprite( const sprite& rhs );
        virtual ~sprite();
        
        void NextFrame( UINT iRate = 1 );
        void Draw( SDL_Surface* sfDest, int iLocX, int iLocY );
        void Reload( char* szFName );
        void Reload( char* szFName, UINT iNFrms, UINT iFrmW );

        void SetColorKey( SDL_Color cCol );
        void SetColorKey( UINT iR, UINT iG, UINT iB );
        void SetAlpha( UINT iA );
        void SetCurrentFrame( UINT iCFrm )  { m_iCurrentFrm = iCFrm; }
        void SetNumFrames( UINT iNFrms )    { m_iNumFrms = iNFrms;   }
        //void SetFrameWidth( UINT iFrmW )    { m_iFrmWidth = iFrmW;   }
        
        SDL_Rect      GetBoundBox()      const { return m_rBndBox;     }
        SDL_Surface*  GetSurface()       const { return m_psfImage;    }
        SDL_Color     GetColorKey()      const { return m_cColorKey;   }
        UINT          GetCurrentFrame()  const { return m_iCurrentFrm; }
        UINT          GetNumFrames()     const { return m_iNumFrms;    }
        UINT          GetFrameWidth()    const { return m_iFrmWidth;   }
        
        //static void NextFrame( UINT iRate = 1 );
};

#endif
SPRITE.CPP
#include <SDL/SDL.h>
#include <SDL/SDL_Image.h>

#include "sprite.h"

sprite::sprite()
{

}
sprite::sprite( char* szFName )
{
    sprite::LoadFile( szFName );
        m_iNumFrms     = 1;
        m_iFrmWidth    = m_psfImage->w;
        m_iCurrentFrm  = 0;
    
    m_rBndBox.x = 0;
    m_rBndBox.y = 0;
    m_rBndBox.w = m_iFrmWidth;
    m_rBndBox.h = m_psfImage->h;
}
sprite::sprite( char* szFName, UINT iNFrms, UINT iFrmW )
{
    sprite::LoadFile( szFName );
        m_iNumFrms     = iNFrms;
        m_iFrmWidth    = iFrmW;
        m_iCurrentFrm  = 0;
        
    m_rBndBox.x = 0;
    m_rBndBox.y = 0;
    m_rBndBox.w = m_iFrmWidth;
    m_rBndBox.h = m_psfImage->h;
}
/*
sprite::sprite( const sprite& rhs )
{
    if ( &rhs == this )
    {
        return;
    }
    //...
}
*/
sprite::~sprite()
{
    if ( m_psfImage == NULL )
    {
        return;
    }
    SDL_SetColorKey( m_psfImage, 0, 0 );
    SDL_FreeSurface( m_psfImage );
    m_psfImage = NULL;
}
void sprite::LoadFile( char* szFName )
{
    if ( m_psfImage != NULL )
    {
        SDL_FreeSurface( m_psfImage );
    }
    SDL_Surface* psfTemp = IMG_Load( szFName );
    if ( psfTemp == NULL )
    {
        return;
    }
    m_psfImage = SDL_DisplayFormat( psfTemp );
    if ( m_psfImage == NULL )
    {
        SDL_FreeSurface( psfTemp );
        return;
    }
    SDL_FreeSurface( psfTemp );
    return;
}
void sprite::Reload( char* szFName )
{
    sprite::LoadFile( szFName );
        m_iNumFrms     = 1;
        m_iFrmWidth    = m_psfImage->w;
        m_iCurrentFrm  = 0;
        
    m_rBndBox.x = 0;
    m_rBndBox.y = 0;
    m_rBndBox.w = m_iFrmWidth;
    m_rBndBox.h = m_psfImage->h;

    return;
}
void sprite::Reload( char* szFName, UINT iNFrms, UINT iFrmW )
{
    sprite::LoadFile( szFName );
        m_iNumFrms     = iNFrms;
        m_iFrmWidth    = iFrmW;
        m_iCurrentFrm  = 0;
        
    m_rBndBox.x = 0;
    m_rBndBox.y = 0;
    m_rBndBox.w = m_iFrmWidth;
    m_rBndBox.h = m_psfImage->h;

    return;
}
void sprite::ApplyColorKey( SDL_Color cCol )
{
    if (
        SDL_SetColorKey(
            m_psfImage,
            SDL_SRCCOLORKEY,
            SDL_MapRGB( m_psfImage->format, cCol.r, cCol.g, cCol.b )
        )
    < 0 )
    {
        return;
    }
    return;
}
void sprite::ApplyAlpha( Uint8 iA )
{
    if (
        SDL_SetAlpha(
            m_psfImage,
            SDL_SRCALPHA | SDL_RLEACCEL,
            iA
        )
    < 0 )
    {
        return;
    }
    return;
}
void sprite::SetColorKey( SDL_Color cCol )
{
    m_cColorKey = cCol;
    sprite::ApplyColorKey( m_cColorKey );
}
void sprite::SetColorKey( UINT iR, UINT iG, UINT iB )
{
    if ( iR > 255 ) { iR = 255; }
    if ( iG > 255 ) { iG = 255; }
    if ( iB > 255 ) { iB = 255; }
    
    m_cColorKey.r = (Uint8)iR;
    m_cColorKey.g = (Uint8)iG;
    m_cColorKey.b = (Uint8)iB;
    sprite::ApplyColorKey( m_cColorKey );
    return;
}
void sprite::SetAlpha( UINT iA )
{
    m_cAlpha = (Uint8)iA;
    sprite::ApplyAlpha( m_cAlpha );
    return;
}
void sprite::NextFrame( UINT iRate )
{
    m_iCurrentFrm += iRate;
    if ( m_iCurrentFrm >= m_iNumFrms )
    {
        m_iCurrentFrm = 0 + ( m_iCurrentFrm - m_iNumFrms );
    }
    return;
}
void sprite::Draw( SDL_Surface* psfDest, int iLocX, int iLocY )
{
    if ( psfDest == NULL )
    {
        return;
    }

    SDL_Rect rSrcBox;
        rSrcBox.x  = (int)( m_iCurrentFrm * m_iFrmWidth );
        rSrcBox.y  = 0;
        rSrcBox.w  = (int)( m_iFrmWidth );
        rSrcBox.h  = m_psfImage->h;

    SDL_Rect rDstBox;
        rDstBox.x  = iLocX;
        rDstBox.y  = iLocY;
        rDstBox.w  = rSrcBox.w;
        rDstBox.h  = rSrcBox.h;

    SDL_BlitSurface( m_psfImage, &rSrcBox, psfDest, &rDstBox );
    
    return;
}
At the moment, this class is missing a lot of functionality that I want to add... but I can't see why it's not working. :-( Does anyone see anything here that I've done wrong?
Advertisement
what did the compil say??
I got no compile errors. The only error message I receive says the program terminated with status 1 (when the program runs properly, it ends with status 0).
Can I ask why you're using protected instead of private? That class isn't inherited, at least as far as your code shows me. Try using private instead.
You have:
UINT          m_iFrmWidth;   //width of each frame

But in the constructor you do:
m_iFrmWidth    = m_psfImage->w;


It should be the image width divided by the number of frames shouldn't it?
I used...
m_iFrmWidth    = m_psfImage->w;
...in that constructor because it's overloaded. With that constructor, the user supplies only a filename and the class assumes that there is no animation, so the frame width is equal to the width of the image surface.

I'll try using a private declaration rather than a protected declaration. I only did it that way because I thought I might derive from this class at some point.
The protected vs private question has nothing to do with the program crashing.

Also, it is possible that the problem is not in the class, but in the code that uses the class. Have you tried running the code through the debugger to find out exactly where it is crashing?

edit - I also noticed that your default constructor doesn't initialize any of the member variables. Thus, your SDL_surface pointer could be pointing to random memory and your other variables could have funky values.
Yeah, changing the protected declaration to private had no effect. :-(

I'll see what I can find with the debugger... but the only code using this class is a little test program that doesn't do much more than display an image and move it via a joystick.
SDL and my debugger both report a "segmentation fault". Any ideas what that means?
An uninitialized pointer comes to mind.

In your LoadFile method, you are checking if m_psfImage is not NULL. If it's not NULL, you do a SDL_FreeSurface. However, since m_psfImage is never initialized to NULL, it could easily have a random value when LoadFile is called.

This topic is closed to new replies.

Advertisement