Problem with class using SDL

Started by
3 comments, last by HJSimpson 17 years, 8 months ago
I have some classes that I am trying to test. They use SDL and draw images or text to the screen. Sprite inherits from Drawable which contains functions for Drawing and resizing the images, Sprite conatins a few functions for moving the sprite around the screen and choosing a frame. I'll post all the code that the test program uses. The problem is that it only draws one sprite, when it should draw two. testSprite won't draw unless backGround is created. backGround doesn't even have to have the image loaded, or anything but a declaration. But backGround won't draw. However, declaring and even attempting to draw a third sprite doesn't remedy the situation with backGround not Drawing. It seems that testSprite is the only one that will draw. Drawable.h and Drawable.cpp

#ifndef DRAWABLE_H
#define DRAWABLE_H
#include "SDL\SDL.h"
#include "SDL\SDL_image.h"
#include <string>

class Drawable
{
private:

protected:
	SDL_Rect destRect, srcRect;
	SDL_Surface *image;
public:
	Drawable(int, int, int, int);
	Drawable(){}
	virtual ~Drawable();
	bool Load(std::string);
	bool Draw(SDL_Surface *);
	void Resize(int, int);
	void Free();
};

#endif

///////////////////////////////////////////////////////////////////

#include "Drawable.h"

Drawable::Drawable(int x=0, int y=0, int h=0, int w=0)
{
	destRect.x=x;
	destRect.y=y;
	destRect.h=h;
	destRect.w=w;
	srcRect.x=x;
	srcRect.y=y;
	srcRect.h=h;
	srcRect.w=w;
}

Drawable::~Drawable()
{
}

bool Drawable::Load(std::string filePath)
{
	image=IMG_Load(filePath.c_str());
	if(image==NULL)
	{
		return false;
	}
	return true;
}

bool Drawable::Draw(SDL_Surface *dest)
{
	if(SDL_BlitSurface(image, &srcRect, dest, &destRect)<0)
	{
		return false;
	}
	return true;
}

void Drawable::Free()
{
	SDL_FreeSurface(image);
}

void Drawable::Resize(int h, int w)
{
	destRect.h=h;
	destRect.w=w;
	srcRect.h=h;
	srcRect.w=w;
}


Sprite.h and Sprite.cpp

#ifndef SPRITE_H
#define SPRITE_H
#include "drawable.h"

class Sprite : public Drawable
{
private:

public:
	Sprite();
	~Sprite();
	void MoveTo(int, int);
	void MoveBy(int, int);
	void GotoFrame(int);
};

#endif

///////////////////////////////////////////////////////

#include "Sprite.h"

Sprite::Sprite()
{
}

Sprite::~Sprite()
{
}

void Sprite::MoveTo(int x, int y)
{
	destRect.x=x;
	destRect.y=y;
}

void Sprite::MoveBy(int x, int y)
{
	destRect.x+=x;
	destRect.y+=y;
}

void Sprite::GotoFrame(int frame)//not used
{
	srcRect.y=srcRect.h*frame;
}


main

#include "SDL\SDL.h"
#include "SDL\SDL_ttf.h"
#include "Sprite.h"

int main(int argc, char* args[])
{
	SDL_Surface *screen;
	bool game;
	SDL_Event e;
	Sprite testSprite, backGround;
	
	/*********************************
	SDL Initialization****************
	*********************************/
	if(SDL_Init(SDL_INIT_VIDEO)<0)
	{
		return 1;//exit if SDL fails to init
	}

	if(TTF_Init()<0)
	{
		return 1;
	}

	screen=SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);

	if(screen==NULL)
	{
		return 1;//exit if screen doen't init
	}

	SDL_WM_SetCaption("Test", NULL);

	/*******************************
	Game Object initialization******
	*******************************/

	if(!testSprite.Load(".\\test.png"))
		return 1;
	if(!backGround.Load(".\\bg.png"))
		return 1;

	testSprite.Resize(40, 40);
	testSprite.MoveTo(30, 30);
	backGround.Resize(480, 640);
	backGround.MoveTo(0, 0);

	/*******************************
	Game Loop***********************
	*******************************/

	game=true;
	while(game)//game loop
	{
		/***********************
		Drawing*****************
		***********************/
		backGround.Draw(screen);
		testSprite.Draw(screen);

		SDL_Flip(screen);	

		/*********************
		Event handling********
		*********************/
		
		SDL_PollEvent(&e);
		switch(e.type)
		{
		case SDL_KEYUP:			
			switch(e.key.keysym.sym)
			{
			case SDLK_ESCAPE:
				game=false;
				break;
			}//end e.key.keysym.sym

			break;//end SDLK_KEYUP
		case SDL_QUIT:
			game=false;
			break;//end SDL_QUIT
		}//end e.type
	}//end game loop
	
	/*************************
	Clean up******************
	*************************/
	
	testSprite.Free();
        backGround.Free();
	SDL_FreeSurface(screen);
	TTF_Quit();
	SDL_Quit();
	return 0;
}


BTW: All of the images do load properly.
Advertisement
The SDL api unfortunatly doesn't support resizing by itself, so perhaps the problem is connected to that. Have the source rect be only initialized by the Load function (image->w and image->h) and touched nowhere else. Otherwise I couldn't see what was going on exactly.

And since you have in C++ automatic destruction of objects, put SDL_FreeImage(image) in the destructor, you can get rid of the free function and all is fine. (this is called raii)
Also change to Sprite constructor to:

Sprite::Sprite()
: image(0) // initialize image to NULL, 0 can be used for that and is recommended.
{
}
By resizing I didn't mean making the actual image smaller, moving and resizing the rectangle inside that it clips from the sprite. Sorry about not being clear.

So, I added the initialization of image to Drawable's constructor. Changed the SDL_FreeSurface to be part of the destructor for Drawable, but this still happens.

If it helps I am using MS VC++ 2005 Express.
So testSprite will be drawn as expected if and only if a backGround is created, while backGround isn't drawn at all? I can't see what could be the problem myself, so I'll leave you with this:
What you can do is to find the bug is:
- use assertions, if you don't know about them: include <cassert>, then assert(image != 0); for example will generate a runtime error pointing out the source of evil if image == 0. Sprinkle your code with them where you expect conditions to be true. Defining NDEBUG will get rid of them when you compile for a release version.
- simplify the test cases down to a version that works, somewhere in between this and your original code lies the bug.
- use a debugger, it can be a help and your IDE is supposed to have quite a good one.

Sorry I couldn't be of more help and good luck.
Thanks DeadXorAlive, I couldn't figure it out all day either, so I will try using assert.

This topic is closed to new replies.

Advertisement