Jump to content
  • Advertisement
Sign in to follow this  
Scribbl3r

Some help for an SDL beginner

This topic is 4723 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

Ok, so I read the first three of Cone3d's tutorials, and decided to write my own Sprite library from scratch. So far I've written a bit of the sprite base class, and I want to test it so I know it is retrieving images correctly. I am using Dev-C++ 4.9.9.2 and I have all the linking parameters from Cone3d's tutorials. So here's my SpriteBase.h. The way I want it to work is it takes in a sprite sheet with all it's frames organized horizontally, and it takes in the width, height, and framecount of the animation. Based on this info, the sprite sheet is cut up into frames and put into a vector of sprites.
#ifndef __SPRITEBASE_H__
#define __SPRITEBASE_H__

#include <stdlib.h>

#include <SDL\SDL.h>

class SpriteBase
{
      public:
             SDL_Surface *Sprite;
             SpriteBase(SDL_Surface *srcArg, int hArg, int wArg, int framecountArg);
      private:
              
              int framecount;
              int h;
              int w;
};

#endif

And here's my SpriteBase.cpp:
#include <stdlib.h>
#include <vector>
#include <SDL\SDL.h>
#include "SpriteBase.h"
using namespace std;
SpriteBase :: SpriteBase(SDL_Surface *srcArg, int hArg, int wArg, int framecountArg)
{
     //set the size of framecount
     framecount = framecountArg;
     //set height and width of each frame
     h = hArg;
     w = wArg;
     //divide up the source surface into frames and place in the Sprite vector
     int x = 0;
     SDL_Surface *temp;
     SDL_Rect *srcRect;
     for(x = 0 ; x < framecount ; x++)
     {
           srcRect->x = x;
           srcRect->y = x;
           srcRect->w = w * (x+1);      
           //get frame from spritesheet
           SDL_BlitSurface(srcArg, srcRect, temp, NULL);
           //place in sprite vector
           SDL_BlitSurface(temp, NULL, Sprite[x], NULL);
     }
     //free surface
     SDL_FreeSurface(temp);
}

My problem is that when I try to compile, I get an error saying "cannot convert `SDL_Surface' to `SDL_Surface*' for argument `3' to `int SDL_UpperBlit(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*)'" This error occurs in SpriteBase.cpp where I try to put the frame from the sprite sheet into a the Sprite vector. Thanks for any help!

Share this post


Link to post
Share on other sites
Advertisement
Ok... unfortunately you've misunderstood a few things along the way, which I'll try to explain. SDL_Surface *Sprite; means that Sprite is a pointer to a single surface. Then you use it like this 'Sprite[x]' which is treating 'Sprite' as if it's an array, which it's not (yet), it's just a bare pointer to the middle of nowhere. (By the way, you shouldn't refer to an array as a vector as they mean subtly different things in C++ - a vector is a dedicated class whereas an array is a built-in type.)

Then, you use SDL_BlitSurface in the hope of copying the surfaces first to temp (another uninitialised pointer), and then to the array. There's a semantic difference here - SDL_BlitSurface copies the pixels from one existing surface and overwrites the pixels of another existing surface - it does not copy 'SDL_Surface' objects themselves, therefore you cannot use it to populate an array (not that the array even exists yet in this case) or to create new surfaces.

What you actually need to use is a function such as SDL_CreateRGBSurface to create each surface, and only then do you use SDL_BlitSurface to populate that surface with pixel data from your original surface. Then add the pointer to the new surface to an array of SDL_Surface*, or preferably a vector for ease of management.

Share this post


Link to post
Share on other sites
Ok, that helps alot, I'll try that.

Here we go... So this is the proper usage? I used SDL_CreateRGBSurface(), then made a pointer to that Surface. I should then place the pixel data in the pointer.
...
//make temp surface

Uint32 rmask,gmask,bmask,amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
SDL_Surface temp;
SDL_Surface *tempPtr = &temp;
tempPtr = SDL_CreateRGBSurface(SDL_HWSURFACE,w,h,32,rmask,gmask,bmask,amask);

SDL_Rect *srcRect;
for(x = 0 ; x < framecount ; x++)
{
srcRect->x = x;
srcRect->y = x;
srcRect->w = w * (x+1);
//get frame from spritesheet
SDL_BlitSurface(srcArg, srcRect, tempPtr, NULL);
//place in sprite vector

Sprite[x] = *tempPtr;
}
//free surface
SDL_FreeSurface(tempPtr);
}
But shouldn't I use an array of SDL_Surface to store the frames as apposed to *SDL_Surface, because the pointers would need something to point to... and the temp surface I'm loading thier data into is reused/freed.

Thanks for the help!

[Edited by - Scribbl3r on June 17, 2005 9:17:54 PM]

Share this post


Link to post
Share on other sites
Hi,
I'm not sure if this is what you want, but if you need multiple frames for your sprite then yes - you're going to need to store multiple SDL_Surfaces someway. I simply used std::vector for storing my CBitmaps. Here's my Sprite.h just for some design ideas :)


// Include once
#ifndef SPRITE_H
#define SPRITE_H

// Includes
#include <vector>
#include "Timer.h"
#include "Graphics.h"


/// This class holds the actual animation frames which must be loaded only
/// once in the program; not once per each sprite! The class also holds
/// useful information about different animation sequences.
class CSpriteBase
{
public:
friend class CSprite;

/// Default Constructor
CSpriteBase();

/// Default Destructor
~CSpriteBase();

/// Adds one image into the list
bool AddBitmap(CGraphics & Graphics, const std::string & Filename);

/// Adds a whole animation sequence into the list from <Filename0.XXX> to end
/// eg. Frame0.bmp, Frame1.bmp, Frame2.bmp, ...,
bool AddSequence(CGraphics & Graphics, const std::string & Filename, unsigned int StartFrame = 0);

/// Sets colorkey for all frames
void SetColorKey(Uint8 Red, Uint8 Green, Uint8 Blue);

/// Clears any current color key from every frame
void ClearColorKey();

/// Sets alpha value for all frames
void SetAlpha(Uint8 Alpha);

private:
// Prevent object copies
/// Copy constructor
CSpriteBase(const CSpriteBase &);

/// '=' operator
CSpriteBase & operator=(const CSpriteBase &);


/// Contains the animation sequences
std::vector< std::vector<unsigned int> > m_AnimSequences;

/// List of all frames
std::vector<CBitmap> m_Frames;

/// Total number of animation sequences
unsigned int m_NumAnims;

/// Total number of frames
unsigned int m_NumFrames;
};


/// a simple sprite class with some animation functionality
class CSprite
{
public:
/// Default Constructor
CSprite();

/// Default Destructor
~CSprite();

/// Creates the sprite from sprite base and the system timer
bool Create(CSpriteBase & Spritebase, CTimer & Timer);

/// Renders the sprite at its position and updates the animation
void Render();

/// Moves the sprite to position (x,y) on the visible screen
void Move(int x, int y);

/// Moves the sprite in relative coordinates
void MoveRel(int dx, int dy);

/// Sets a new animation
void SetAnimation(unsigned int SequenceNum);

/// Sets a new animation (with speed)
void SetAnimation(unsigned int SequenceNum, double Speed);

/// Stops the animation
void StopAnimation();

/// Stops the animation at frame X of current sequence
void StopAnimation(unsigned int Frame);

/// Continues previous animation
void ContinueAnimation();

/// Sets the animation speed
void SetSpeed(double Speed);

/// Gets the animation speed
double GetSpeed() const;

/// Sets the visibility mode
void SetVisible(bool Visible);

/// Is the sprite visible?
bool IsVisible() const;

/// Sets the looping mode
void SetLooping(bool Loop);

/// Is the animation looping?
bool IsLooping() const;


/// Gets the X position of the sprite
int GetX() const;

/// Gets the Y position of the sprite
int GetY() const;

/// Gets the width of the current frame
int GetWidth() const;

/// Gets the height of the current frame
int GetHeight() const;

private:
/// X Coordinate
int m_x;

/// Y Coordinate
int m_y;

/// Width of the first frame!
int m_Width;

/// Height of the first frame!
int m_Height;

/// Current frame to render
double m_CurrentFrame;

/// Current animation sequence running
unsigned int m_CurrentAnim;

/// Current animation speed
double m_AnimSpeed;

/// Is the animation running?
bool m_Animating;

/// Is the animation looping?
bool m_Looping;

/// Is this sprite visible?
bool m_Visible;

/// Pointer to the sprite base (bitmap holder)
CSpriteBase * m_SpriteBase;

/// Pointer to the system timer
CTimer * m_Timer;
};


// Include once
#endif



Also, when creating the SDL_Surface, you should make sure that you're using the same format as your display format by using SDL_DisplayFormat(); (anyone correct me If I'm wrong)

Share this post


Link to post
Share on other sites
Quote:
Original post by Scribbl3r
But shouldn't I use an array of SDL_Surface to store the frames as apposed to *SDL_Surface, because the pointers would need something to point to... and the temp surface I'm loading thier data into is reused/freed.


No, you shouldn't really use 'SDL_Surface' objects directly. SDL creates them and holds them for you, and you should just pass around and store the pointers (and call SDL_FreeSurface on them when you're done). So don't create them on the stack like this 'SDL_Surface temp;', just create a pointer and point that to the result of SDL_CreateRGBSurface. Now store that pointer and keep hold of it for as long as you want to use that surface.

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!