Advertisement

SDL and Cone3D Lesson 3: Sprites

Started by October 18, 2004 09:33 AM
4 comments, last by graveyard filla 19 years, 10 months ago
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.
- A momentary maniac with casual delusions.
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.
FTA, my 2D futuristic action MMORPG
Advertisement
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();}
- A momentary maniac with casual delusions.
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.
FTA, my 2D futuristic action MMORPG
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?
- A momentary maniac with casual delusions.
yes, a console application.
FTA, my 2D futuristic action MMORPG

This topic is closed to new replies.

Advertisement