Jump to content
  • Advertisement
Sign in to follow this  
econobeing

Is this a good idea? (SDL)

This topic is 4408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

i don't have all of it planned out, it's just kind of a general idea right now. but i'm thinking about making some files that kind of replace SDL functions with my own(which would use SDL's). re-do the image loading function, make an image loading function for animated images(to store each frame and whatnot), make a function so it's easier to plot pixels on the screen, etc. not just limit it to graphics but input, sound, and other things. i kind of get the feeling that i'm SUPPOSED to be doing this. yet at the same time i get the feeling that it would be doing too much... thoughts, opinions, insults?

Share this post


Link to post
Share on other sites
Advertisement
oh, another question.

how can i get rid of the console window when using VC2005 Express?

in Code::Blocks and Dev-C++ there's an option in the project properties where you can choose GUI as the type. i couldn't find an option like that in VC2005

Share this post


Link to post
Share on other sites
Quote:
Original post by econobeing
i don't have all of it planned out, it's just kind of a general idea right now.

but i'm thinking about making some files that kind of replace SDL functions with my own(which would use SDL's). re-do the image loading function, make an image loading function for animated images(to store each frame and whatnot), make a function so it's easier to plot pixels on the screen, etc.

not just limit it to graphics but input, sound, and other things.

i kind of get the feeling that i'm SUPPOSED to be doing this. yet at the same time i get the feeling that it would be doing too much...

thoughts, opinions, insults?


That would be a pretty bad idea. SDL handles things in a cross-platform way, most likely low-level. If you do so you have to recompile the whole SDL library, and then use that .dll for your games.

Instead, I suggest you do something like a wrapper library. Use SDL functions in your wrapper library and use your library then.

Share this post


Link to post
Share on other sites
I think its a fine idea to create a library of your own functions which use SDL's functions. It can simplify things like pixel plotting and whatnot. Just think of it as writing your own SDL engine, because basically, that's what you're doing. Plus, if you are writing your own game with SDL, you'll probably find yourself writing your own functions anyway. This way you can just re-use them.

Share this post


Link to post
Share on other sites
Quote:
Original post by agi_shi
Quote:
Original post by econobeing
i don't have all of it planned out, it's just kind of a general idea right now.

but i'm thinking about making some files that kind of replace SDL functions with my own(which would use SDL's). re-do the image loading function, make an image loading function for animated images(to store each frame and whatnot), make a function so it's easier to plot pixels on the screen, etc.

not just limit it to graphics but input, sound, and other things.

i kind of get the feeling that i'm SUPPOSED to be doing this. yet at the same time i get the feeling that it would be doing too much...

thoughts, opinions, insults?


That would be a pretty bad idea. SDL handles things in a cross-platform way, most likely low-level. If you do so you have to recompile the whole SDL library, and then use that .dll for your games.

Instead, I suggest you do something like a wrapper library. Use SDL functions in your wrapper library and use your library then.



Maybe I am just misunderstanding him, or maybe I am misunderstanding you, but I don't think he is talking about going in SDL's source code and changing it via that way. I think he is talking about creating a little SDL Engine really. Is that what ya mean dude? Sorry, if I am just wrong.


Chad

Share this post


Link to post
Share on other sites
yep, thats what i meant. i don't want to actually modify the actualy SDL code, i just want to make functions, classes, etc. that use SDL to make it easier to program.

Share this post


Link to post
Share on other sites
It is a good idea if you intend to write code that extends the functionality of SDL. It is a bad idea to write code that replaces SDL, but has the same functionality -- in other words, don't re-invent the wheel.

I've written some code for my own stuff that extends SDL. This code implements sprites and animated sprites, and a few handy functions. If you can use it, go ahead. I don't claim that it is bug-free however.

sdlx.h

#include <SDL.h>

namespace Sdlx
{
//! Loads an image file.
SDL_Surface * LoadImage( char const * filename );

//! Loads an image file and applies a color key
SDL_Surface * LoadColorKeyedImage( char const * filename, SDL_Color key ) ;

//! Idle processing callback.
typedef bool (*EventLoopIdleCallback)();

//! Event loop event handler
typedef bool (*EventLoopEventHandler)( SDL_Event const & event );

//! Handle events until a SDL_QUIT event is received.
void EventLoop( EventLoopEventHandler pEH = 0, EventLoopIdleCallback pCB = 0 );

//! Returns a color with the specified values
SDL_Color MakeColor( int red, int green, int blue );

//! Returns a rect with the specified values
SDL_Rect MakeRect( int x, int y, int w, int h );

} // namespace Sdlx





sdlx.cpp

#include "precompiledheaders.h"
#include "Sdlx.h"

namespace
{

bool DefaultEventLoopEventHandler( SDL_Event const & event )
{
return ( event.type != SDL_QUIT );
}


} // anonymous namespace


namespace Sdlx
{




//! This function loads an image file and converts it to the format of the display.
//! All image formats supported by SDL_image can be loaded. Currently, they are:
//! - BMP
//! - JPEG
//! - PNG
//! - GIF
//! - TGA
//! - and more
//!
//! @param filename name of the file to load
//!
//! @return pointer to the loaded file, or 0 if error

SDL_Surface * LoadImage( char const * filename )
{
SDL_Surface * loadedImage = 0;
SDL_Surface * image = 0;

loadedImage = IMG_Load( filename );

if ( loadedImage != 0 )
{
image = SDL_DisplayFormat( loadedImage ); // Create an optimized image from the loaded image
SDL_FreeSurface( loadedImage ); // Free the old image
}

return image;
}



//! This function loads an image file and converts it to the format of the display. In addition, a color key is
//! specified.
//!
//! All image formats supported by SDL_image can be loaded. Currently, they are:
//! - BMP
//! - JPEG
//! - PNG
//! - GIF
//! - TGA
//! - and more
//!
//! @param filename name of the file to load
//!
//! @return pointer to the loaded file, or 0 if error

SDL_Surface * LoadColorKeyedImage( char const * filename, SDL_Color key )
{
SDL_Surface * image = LoadImage( filename );

if ( image != 0 )
{
Uint32 colorkey = SDL_MapRGB( image->format, key.r, key.g, key.b );
SDL_SetColorKey( image, SDL_RLEACCEL | SDL_SRCCOLORKEY, colorkey );
}

return image;
}




//! This function handles SDL events until a SDL_QUIT event is received. If an idle processing callback is
//! specified, it is called whenever there are no events to process. If the callback returns @c false, then
//! it will not be called again until after the next event occurs.
//!
//! @param pEH Event Handler callback
//! @param pIdle Idle processing callback

void EventLoop( EventLoopEventHandler pEH/* = 0*/, EventLoopIdleCallback pIdle/* = 0*/ )
{
bool done = false;
bool skipIdle = false;

if ( pEH == 0 )
{
pEH = DefaultEventLoopEventHandler;
}

while ( !done )
{
SDL_Event event;

// Get an event. If there is none to process, then if we are skipping the idle function then
// just sleep, otherwise call the idle function.

if ( SDL_PollEvent( &event ) != 0 )
{
// Call the event handler. If it returns false, then we should exit.
done = !(*pEH)( event );

skipIdle = false; // Now that we have processed a message, start calling the callback function again.
}
else if ( skipIdle || pIdle == 0 )
{
SDL_Delay( 0 );
}
else
{
// Call the idle function. If it returns false, it no longer needs to be called -- set 'skipIdle' so it
// won't be called again until after another message is processed.

skipIdle = !(*pIdle)();
}
}
}




//! This function is basically a convenience. SDL structs lack constructors, so this acts as a constructor for
//! @c SDL_Color.
//!
//! @param red red component. The valid range is 0 - 255.
//! @param green green component. The valid range is 0 - 255.
//! @param blue blue component. The valid range is 0 - 255.

SDL_Color MakeColor( int red, int green, int blue )
{
SDL_Color color = { red, green, blue };

return color;
}




//! This function is basically a convenience. SDL structs lack constructors, so this acts as a constructor for
//! @c SDL_Rect.
//!
//! @param x x
//! @param y y
//! @param w width
//! @param h height

SDL_Rect MakeRect( int x, int y, int w, int h )
{
SDL_Rect rect = { x, y, w, h };

return rect;
}


} // namespace Sdlx





Sprite.h

#include "Sdlx.h"

#include <SDL.h>

#include <vector>

namespace Sdlx
{

class SpriteAnimationGroup;



//! A sprite
//
//! A sprite is a 2D rectangular image that has a location on the display. The image is generally implemented as a
//! sub-region of a "sheet". The sprite also has an origin specified as an offset from the UL corner.

class Sprite
{
public:
//! Default constructor
Sprite();

//! Constructor
Sprite( SDL_Surface * sheet,
SDL_Rect const & rect = MakeRect( 0, 0, 0, 0 ),
int offsetX = 0,
int offsetY = 0,
float x = 0,
float y = 0 );

// Destructor
virtual ~Sprite();

//! Draws the sprite
void Draw( SDL_Surface * dst ) const;

float m_x; //!< Location of the sprite's origin on the display
float m_y; //!< Location of the sprite's origin on the display
SDL_Rect m_rect; //!< Location and size of the sprite in the image
int m_offsetX; //!< Offset from the the UL corner to the sprite's origin
int m_offsetY; //!< Offset from the the UL corner to the sprite's origin

private:

SDL_Surface * m_sheet; // The sheet containing the sprite's image
};




//! An animated sprite
//
//! This class is a sprite whose image is animated. Animations are basically a list of frames on a sheet and the
//! durations for each frame. An animated sprite can have several different animations, though all frames of the
//! animation must come from a single sheet. The animations can stop on the last frame, can loop, or can play back
//! and forth ( "ping-pong" ).
//!
//! Animation group
//!
//! An animation "group" consists of a list of animations and a list of all the images to used in the animations.
//! The images are all sub-regions of a single sheet. The animations reference the list of images, and an image
//! can be used in several animations and even multiple times in a single animation.
//!
//! Animation
//!
//! An animation is simply a list of frames and a mode that determines what to do when the end of the list of
//! frames is reached. Each frame contains the index of its image (in the image list) and its
//! duration.

class AnimatedSprite : public Sprite
{
friend class SpriteFactory;

public:

//! Direction of playback
enum Direction
{
DIR_FORWARD, //!< Play the animation forward
DIR_BACKWARD //!< Play the animation backward
};

//! A frame of an animation
struct Frame
{
int index; //!< The index of the image in the image list
float time; //!< The duration of the frame
};

//! An animation
struct Animation
{
//! A vector of animation frames
typedef std::vector< Frame > FrameList;

//! The behavior of an animation when it reaches the end of the animation
enum Mode
{
MODE_ONCE, //!< Freeze on the last frame
MODE_LOOP, //!< Loop forever
MODE_PINGPONG //!< When the beginning or end is reached, reverse direction
};

Mode mode; //!< Looping behavior
FrameList frames; //!< The frames of the animation
};

//! A set of animations using a common sheet
struct AnimationGroup
{
//! A frame of an animation
struct Image
{
SDL_Rect rect; //!< Location and size within the sheet
int offsetX, offsetY; //!< Offset to the sprite's origin from the UL corner of the sprite
};

typedef std::vector< Image > ImageList; //!< A vector of images
typedef std::vector< Animation > AnimationList; //!< A vector of animations

//! Default constructor
AnimationGroup() {}

//! Constructor
AnimationGroup( ImageList const & images, AnimationList const & animations );

ImageList images; //!< All the images used in the group
AnimationList animations; //!< All the animations in this group
};

//! Default constructor
AnimatedSprite();

//! Constructor
AnimatedSprite( SDL_Surface * sheet, AnimationGroup const * animations, float x = 0, float y = 0 );

// Destructor
virtual ~AnimatedSprite();

//! Starts an animation
void PlayAnimation( int index, Direction direction = DIR_FORWARD );

//! Advances the time (in seconds)
void AdvanceTime( float elapsed );

//! Sets the time (in seconds)
void SetTime( float time );

//! Sets the current animation frame
void SetFrame( int intex );

//! Returns the current animation index
int GetAnimation() const { return m_currentAnimation; }

//! Returns the current time (in seconds)
float GetTime() const { return m_time; }

//! Returns the current animation frame
int GetFrame() const { return m_currentFrame; }

//! Updates the state of the sprite animation
void Service( float elapsedTime );

private:

AnimationGroup const * m_pAnimations; // The animation group
int m_currentAnimation; // The index of the current animation
int m_currentFrame; // The index of the current frame
float m_time; // The current position of the animation
float m_frameTime; // The time from the start of the current frame
Direction m_direction; // The direction that the animation is playing
};

} // namespace Sdlx





Sprite.cpp

#include "PrecompiledHeaders.h"

#include "Sprite.h"

namespace Sdlx
{



Sprite::Sprite()
{
}




//! @param sheet SDL_Surface containing the sprite's image
//! @param rect The location and size of the sprite's image on the sheet
//! @param offsetX,offsetY Offset to the origin of the sprite
//! @param x,y Initial location of the sprite

Sprite::Sprite( SDL_Surface * sheet,
SDL_Rect const & rect/* = MakeRect( 0, 0, 0, 0 )*/,
int offsetX/* = 0*/,
int offsetY/* = 0*/,
float x/* = 0*/,
float y/* = 0*/ )
: m_sheet( sheet ),
m_rect( rect ),
m_offsetX( offsetX ),
m_offsetY( offsetY ),
m_x( x ),
m_y( y )
{
}



Sprite::~Sprite()
{
}




//!
//! @param dst destination surface

void Sprite::Draw( SDL_Surface * dst ) const
{
int rv;

SDL_Rect position = { int( m_x - m_offsetX + 0.5f ), int( m_y - m_offsetY + 0.5f ), 0, 0 };
SDL_Rect const * pRect = ( m_rect.w > 0 && m_rect.h > 0 ) ? &m_rect : NULL;

rv = SDL_BlitSurface( m_sheet, const_cast< SDL_Rect * >( pRect ), dst, &position );
assert( rv == 0 );
}




AnimatedSprite::AnimatedSprite()
: m_pAnimations( 0 ),
m_currentAnimation( 0 ),
m_currentFrame( 0 ),
m_time( 0.0f ),
m_frameTime( 0.0f ),
m_direction( DIR_FORWARD )
{
}






//!
//! @param sheet SDL_Surface containing the sprite's animation frames
//! @param animations Description of the sprite's animations
//! @param x,y Initial location of the sprite
//!
//! @note The sprite does not assume ownership of the animation group, so it can be shared by many sprites.

AnimatedSprite::AnimatedSprite( SDL_Surface * sheet,
AnimationGroup const * animations,
float x/* = 0*/,
float y/* = 0*/ )
: Sprite( sheet, MakeRect( 0, 0, 0, 0 ), 0, 0, x, y ),
m_pAnimations( animations ),
m_currentAnimation( 0 ),
m_currentFrame( 0 ),
m_time( 0.0f ),
m_frameTime( 0.0f ),
m_direction( DIR_FORWARD )
{
assert( animations != 0 );
}




AnimatedSprite::~AnimatedSprite()
{
}




//! This function starts a sprite's animation. The initial frame depends on the direction of play.
//!
//! @param index Which animation to play
//! @param direction Which direction to play the animation

void AnimatedSprite::PlayAnimation( int index, Direction direction/* = DIR_FORWARD*/ )
{
assert( index >= 0 && index < int( m_pAnimations->animations.size() ) );

Animation const & animation = m_pAnimations->animations[ index ]; // Convenience
Animation::FrameList const & frames = animation.frames; // Convenience

m_currentAnimation = index;
m_direction = direction;
m_currentFrame = ( direction == DIR_FORWARD ) ? 0 : int( frames.size() ) - 1;
m_time = 0.0f;
m_frameTime = 0.0f;

// Set the image location and size according to the current frame

Frame const & frame = frames[ m_currentFrame ]; // Convenience
AnimationGroup::ImageList const & images = m_pAnimations->images; // Convenience
AnimationGroup::Image const & image = images[ frame.index ]; // Convenience

m_rect = image.rect;
m_offsetX = image.offsetX;
m_offsetY = image.offsetY;
}




//! This function sets the animation time to an absolute value and updates the animation to reflect the new time.
//!
//! @param time new time
//!
//! @note If the mode is ping-pong, then the initial direction is assumed to be forward.

void AnimatedSprite::SetTime( float time )
{
Animation const & animation = m_pAnimations->animations[ m_currentAnimation ]; // Convenience

if ( animation.mode == Animation::MODE_PINGPONG )
{
m_direction = DIR_FORWARD;
}

PlayAnimation( m_currentAnimation, m_direction );
AdvanceTime( time );
}




//! This function advances the animation by the specified amount of time
//!
//! @param elapsed elapsed time (must be >= 0)

void AnimatedSprite::AdvanceTime( float elapsed )
{
assert( elapsed >= 0.0f );
assert( m_currentAnimation >= 0 && m_currentAnimation < int( m_pAnimations->animations.size() ) );

Animation const & animation = m_pAnimations->animations[ m_currentAnimation ]; // Convenience
Animation::FrameList const & frames = animation.frames; // Convenience

if ( elapsed <= 0.0f )
{
return;
}

float e = elapsed + m_frameTime;

// Set the initial parameters based on the current direction

int step;
int first;
int last;

switch ( m_direction )
{
case DIR_FORWARD:
step = +1;
first = 0;
last = int( frames.size() ) - 1;
break;
case DIR_BACKWARD:
step = -1;
first = int( frames.size() ) - 1;
last = 0;
break;
}

// Step through the animation until the correct frame is reached

while ( e > 0.0f )
{
float currentFrameTime = frames[ m_currentFrame ].time;

if ( e >= currentFrameTime )
{
if ( m_currentFrame * step < last * step )
{
m_currentFrame += step;
}
else
{
if ( animation.mode == Animation::MODE_LOOP )
{
m_currentFrame = first;
}
else if ( animation.mode == Animation::MODE_PINGPONG )
{
m_direction = ( m_direction == DIR_FORWARD ) ? DIR_BACKWARD : DIR_FORWARD;
step = -step;
std::swap( first, last );
}
}
}
else
{
m_frameTime = e;
}

e -= currentFrameTime;
}

// Set the image location and size according to the current frame

Frame const & frame = frames[ m_currentFrame ]; // Convenience
AnimationGroup::ImageList const & images = m_pAnimations->images; // Convenience
AnimationGroup::Image const & image = images[ frame.index ]; // Convenience

m_rect = image.rect;
m_offsetX = image.offsetX;
m_offsetY = image.offsetY;

// Save the time

m_time += elapsed;
}




//! This function sets the current animation to a specific frame (as opposed to a specific time). The running time
//! of the animation is then set to correspond to the specified frame.
//!
//! @param index Desired frame
//!
//! @note If the mode is ping-pong, then the initial direction is assumed to be forward.

void AnimatedSprite::SetFrame( int index )
{
Animation const & animation = m_pAnimations->animations[ m_currentAnimation ]; // Convenience
Animation::FrameList const & frames = animation.frames; // Convenience

assert( index >= 0 && index < int( frames.size() ) - 1 );

m_time = 0.0f;

if ( animation.mode == Animation::MODE_PINGPONG )
{
m_direction = DIR_FORWARD;
}

switch ( m_direction )
{
case DIR_FORWARD:
for ( int i = 0; i < index; ++i )
{
m_time += frames.time;
}
break;

case DIR_BACKWARD:
for ( int i = int( frames.size() ) - 1; i > index; ++i )
{
m_time += frames.time;
}
break;
}

m_currentFrame = index;
m_frameTime = 0.0f;

// Set the image location and size according to the current frame

Frame const & frame = frames[ m_currentFrame ]; // Convenience
AnimationGroup::ImageList const & images = m_pAnimations->images; // Convenience
AnimationGroup::Image const & image = images[ frame.index ]; // Convenience

m_rect = image.rect;
m_offsetX = image.offsetX;
m_offsetY = image.offsetY;
}



//! This function will update the animation based on the amount of time that has elapsed since it was last called.
//!
//! @param elapsedTime Time elapsed since this function was last called (must be >= 0)

void AnimatedSprite::Service( float elapsedTime )
{
assert( elapsedTime >= 0.0f );

AdvanceTime( elapsedTime );
}




//! @param images List of images used in the animations
//! @param animations List of animations

AnimatedSprite::AnimationGroup::AnimationGroup( ImageList const & images, AnimationList const & animations )
: images( images ),
animations( animations )
{
}

} // namespace Sdlx







PreompiledHeaders.h

#include <SDL.h>
#include <SDL_image.h>
#include <cassert>
#include <vector>
#include <utility>





Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!