Sign in to follow this  
Rhaal

SDL and Cone3D Lesson 3: Sprites

Recommended Posts

Rhaal    754
I've been stuck on this for a couple days now. Here's a link to the tutorial I tried to follow: http://cone3d.gamedev.net/cgi-bin/index.pl?page=tutorials/gfxsdl/tut3 Here's my program. I pretty much went word for word with what that page said to do. Here is my source and data files: http://www.tcbembroidery.com/colin/cpp/orex.zip Here is just the source
//CSprite.h
#ifndef __CSPRITE_H__
#define __CSPRITE_H__

#include "CSpriteBase.h"

class CSprite
{
 public:
	 int init(CSpriteBase *base, SDL_Surface *screen);
	 void draw();
	 void clearBG();
	 void updateBG();

	 void setFrame(int nr) { mFrame = nr; }
	 int getFrame() { return mFrame; }

	 void setSpeed(float nr) { mSpeed = nr; }
	 float getSpeed() { return mSpeed; }

	 void toggleAnim() { mAnimating = !mAnimating; }
	 void startAnim() { mAnimating = 1; }
	 void stopAnim() { mAnimating = 0; }
	 void rewind() { mFrame = 0; }

	 void xadd(int nr) { mX+=nr; }
	 void yadd(int nr) { mY+=nr; }
	 void xset(int nr) { mX=nr; }
	 void yset(int nr) { mY=nr; }
	 void set(int xx, int yy) { mX=xx; mY=yy; }

 private:
	 int mFrame;
	 int mX, mY, mOldX, mOldY;
	 int mAnimating;
	 int mDrawn;
	 float mSpeed;
	 long mLastupdate;

	 CSpriteBase *mSpriteBase;
	 SDL_Surface *mBackreplacement;
	 SDL_Surface *mScreen;
};

#endif

//CSpriteBase.h
#ifndef __CSPRITEBASE_H__
#define __CSPRITEBASE_H__


#include <SDL/SDL.h>

struct CSpriteFrame
{
	SDL_Surface *image;
	int pause;
};

class CSpriteBase
{
 public:
	 ~CSpriteBase();
	 int init(char *dir);

	 CSpriteFrame	*mAnim;
	 int mBuilt, mNumframes, mW, mH;
};
#endif

//CSprite.cpp
#include "CSprite.h"

int CSprite::init(CSpriteBase *base, SDL_Surface *screen)
{
	mSpriteBase = base;
	if(mSpriteBase->mBuilt)
	{
		if(mSpriteBase->mNumframes>1) mAnimating=1;
		mBackreplacement = 
			SDL_DisplayFormat(mSpriteBase->mAnim[0].image);
	}
	mScreen = screen;

	return 0;
}

void CSprite::clearBG()
{
	if(mDrawn==1)
	{
		SDL_Rect dest;
		dest.x = mOldX;
		dest.y = mOldY;
		dest.w = mSpriteBase->mW;
		dest.h = mSpriteBase->mH;
		SDL_BlitSurface(mBackreplacement, NULL, mScreen, &dest);
	}
}

void CSprite::updateBG()
{
	SDL_Rect srcrect;
	srcrect.w = mSpriteBase->mW;
	srcrect.h = mSpriteBase->mH;
	srcrect.x = mX;
	srcrect.y = mY;
	mOldX=mX;mOldY=mY;
	SDL_BlitSurface(mScreen, &srcrect, mBackreplacement, NULL);
}

void CSprite::draw()
{
	if(mAnimating == 1)
	{
		if(mLastupdate+mSpriteBase->mAnim[mFrame].pause*mSpeed<
                                                SDL_GetTicks())
		{
			mFrame++;
			if(mFrame>mSpriteBase->mNumframes-1) mFrame=0;
			mLastupdate = SDL_GetTicks();
		}
	}

	if(mDrawn==0) mDrawn=1;

	SDL_Rect dest;
	dest.x = mX; dest.y = mY;
	SDL_BlitSurface(mSpriteBase->mAnim[mFrame].image, NULL, mScreen, 
                                                           &dest);
}

//CSpriteBase.cpp
#include <SDL/sdl.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <string>
#include "CSpriteBase.h"

CSpriteBase::~CSpriteBase()
{
	delete[] mAnim;
}

int CSpriteBase::init(char *dir)
{
	char buffer[255];
	char filename[255];
	char name[255];
	int pause=0, r=0, g=0, b=0;
	FILE *fp;

	// Get info from info file
	sprintf(filename, "%s/info", dir);
	fp = fopen(filename, "r");
	fgets(buffer, 255, fp);
	sscanf(buffer, "FILES: %d", &mNumframes);

	mAnim = new CSpriteFrame[mNumframes];

	mBuilt = 1;
	int count = 0;

	// Loop through info file
	while(!feof(fp) && count < mNumframes)
	{
		fgets(buffer, 255, fp);
		if(buffer[0] != '#' && buffer[0] != '\r' && buffer[0] != '\0'
			&& buffer[0] != '\n' && strlen(buffer) != 0)
		{
			// Since we now know that the line will be useful, we'll extract the name of the frame image, 
			// the milliseconds to pause after displaying it and the r, g and b of the transparent color.
			// We'll then make the string filename equal the full path to the frame file and load it in.
			sscanf(buffer, "%s %d %d %d %d", name, &pause, &r, &g, &b);
			sprintf(filename, "%s/%s", dir, name);

			SDL_Surface *temp;
			temp = SDL_LoadBMP(filename);

			// Now we'll check if the transparent color's r component is greater than or equal to zero. If so, we'll make temp transparent. But if r would be -1 or so, then we wouldn't have made the surface transparent.
			if(r >= 0)
				SDL_SetColorKey(temp, SDL_SRCCOLORKEY, SDL_MapRGB(temp->format, r, g, b));

			mAnim[count].image = SDL_DisplayFormat(temp);
			SDL_FreeSurface(temp);

			mAnim[count].pause = pause;
			if(!mW) mW = mAnim[count].image->w; 
			if(!mH) mH = mAnim[count].image->h;

			count ++;
		}
	}

	// close the file
	fclose(fp);
	return 0;
}

//main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
#include <SDL/SDL.h>

#include "CSpriteBase.h"
#include "CSprite.h"

SDL_Surface *screen, *back;
CSpriteBase swordbase;
CSpriteBase moonbase;
CSprite sword;
CSprite moon;

SDL_Surface * ImageLoad(char *file)
{
	SDL_Surface *temp1, *temp2;
	temp1 = SDL_LoadBMP(file);
	temp2 = SDL_DisplayFormat(temp1);
	SDL_FreeSurface(temp1);
	return temp2;
}

int InitImages()
{
	back = ImageLoad("data/bg.bmp");
	return 0;
}

void DrawIMG(SDL_Surface *img, int x, int y)
{
	SDL_Rect dest;
	dest.x = x;
	dest.y = y;
	SDL_BlitSurface(img, NULL, screen, &dest);
}

void DrawBG()
{
	DrawIMG(back, 0, 0);
	SDL_Flip(screen);
	DrawIMG(back, 0, 0);
}

void DrawScene()
{
	moon.clearBG();
	sword.clearBG();

	moon.updateBG();
	sword.updateBG();

	moon.draw();
	sword.draw();

	SDL_Flip(screen);
}

void oxGameLoop()
{

	// Initialize SDL video and audio systems.
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
	atexit(SDL_Quit);

	// Pointer to keyboard keys.
	Uint8* keys;

	// Create a screen surface.
	screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);

	// Initialize images and sprites.
	swordbase.init("data/sword");
	moonbase.init("data/moon");

	moon.init(&moonbase, screen);
	moon.set(480, 50);
	moon.setSpeed(1);

	sword.init(&swordbase, screen);
	sword.set(150, 300);
	sword.setSpeed(1);

	//Hide the mouse cursor
	SDL_ShowCursor(0);

	InitImages();
	DrawBG();

	// Main game loop.
	bool bRunning = 1;
	while(bRunning)
	{
		SDL_Event event;
		while(SDL_PollEvent(&event))
		{
			if(event.type == SDL_QUIT)
				bRunning = 0;
			if(event.type == SDL_KEYDOWN)
			{
				if(event.key.keysym.sym == SDLK_ESCAPE)
					bRunning = 0;
				if(event.key.keysym.sym == SDLK_SPACE)
					moon.toggleAnim();
			}
		}

		// input
		keys = SDL_GetKeyState(NULL);
		if (keys[SDLK_UP]) { sword.yadd(-1); }
		if (keys[SDLK_DOWN]) { sword.yadd(1); }
		if (keys[SDLK_LEFT]) { sword.xadd(-1); }
		if (keys[SDLK_RIGHT]) { sword.xadd(1); }

		DrawScene();

	}// End main game loop.
}

//winmain.cpp
#include <windows.h>
#include <windowsx.h>
#define WIN32_LEAN_AND_MEAN

void oxGameLoop();

LRESULT CALLBACK MsgHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam){
	switch(msg)
	{
	case WM_DESTROY:
		{
			PostQuitMessage(0);
			return(0);
		}
	default: break;
	}

	return(DefWindowProc(hwnd, msg, wparam, lparam));
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, 
				   LPSTR lpCmdLine, int nCmdShow)
{
	oxGameLoop();
}

Now you'll see stuff in there like standard headers that I don't need. This is in from suggestions by other users at the bottom of that page. The program will compile fine, but when running only shows a black window before crashing.

Share this post


Link to post
Share on other sites
first of all, why are you using a WinMain, and other windows specific things? one of the best parts about SDL is you dont have to touch the win32 API, and stay cross platform.

secondly, thats a lot of code you posted and you cant expect someone to look through it all and try to debug your code for you. what compiler are you using? you should look at the call stack and find out what function the game was running when the program crashed. this will make finding the problem 10x easier. most likely its an invalid pointer that is causing the crash, but like i said, the call stack will tell you the exact line that it crashed at. from there it should be easy to tell what the problem is.

Share this post


Link to post
Share on other sites
Rhaal    754
Quote:
Original post by graveyard filla
first of all, why are you using a WinMain, and other windows specific things? one of the best parts about SDL is you dont have to touch the win32 API, and stay cross platform.

secondly, thats a lot of code you posted and you cant expect someone to look through it all and try to debug your code for you. what compiler are you using? you should look at the call stack and find out what function the game was running when the program crashed. this will make finding the problem 10x easier. most likely its an invalid pointer that is causing the crash, but like i said, the call stack will tell you the exact line that it crashed at. from there it should be easy to tell what the problem is.


I'm sorry. I had doubts about this as I was posting it when trying to rush out the door this morning. But, like I said, it compiles and builds fine. It was worse and I tried to clean it up a little. When I get home to a compiler this evening I'll comment it and run it through debug, but that's still something I'm getting used to. (VS.NET 7)

I realized the message handler is not needed but I still need a WinMain if I'm making a Windows program right? If I try to create a windows program and just write a main() function the compiler will flag it. All my WinMain does is call my "real" main function.

I was just hoping that someone had gone through the same tutorial and had the same problem but with a solution.


int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
oxGameLoop();
}

Share this post


Link to post
Share on other sites
no, you dont need a winmain. instead, just use a regular main(), only it should receive an int and a **char... like this:

int main(int argc, char *argv[])

your using VS 7.1? thats awesome then... run it in debug, and when it crash's, look in the window on the bottom right side, this is the call stack.. it will show all the functions that were called before the program crashed, including the function that was called when it crashed, in fact, the IDE should have you left off to the line it crashed at anyway.. if you post this line, i could help you figure it out.

Share this post


Link to post
Share on other sites
Rhaal    754
Quote:
Original post by graveyard filla
no, you dont need a winmain. instead, just use a regular main(), only it should receive an int and a **char... like this:

int main(int argc, char *argv[])

your using VS 7.1? thats awesome then... run it in debug, and when it crash's, look in the window on the bottom right side, this is the call stack.. it will show all the functions that were called before the program crashed, including the function that was called when it crashed, in fact, the IDE should have you left off to the line it crashed at anyway.. if you post this line, i could help you figure it out.


I'll check that out when I get a chance. So if I don't need a winmain function, what type of application do I select when setting up the IDE, console?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this