🔒 Locked
Using SDL_Surface with an array
Advertisement
Original Post
Hello all, I'm fairly new to C++(a few months). A few days ago I started playing around with SDL and got pretty good at it. But I'm now making an 'engine', which it shouldn't even be called. But on to the problem. What I have is a function that reads the map data, the format is as followed: MapSizeX MapSizeY MouseShow Number of Enemys EnemySpawnX EnemySpawnY -Etc After it reads the text file, it goes to this function: void CMap::DrawScene() { DrawIMG(background, PlayerXPos, PlayerYPos, 32, 32, PlayerXPos, PlayerYPos); DrawIMG(player, PlayerXPos, PlayerYPos); printf("Drawing enemys...\n"); for( int i = 0; i < NumOfEnemys; i++ ) { printf("Drawing image..\n"); if( Enemy == 1 ) { DrawIMG(enemy[1], EnemyX[1], EnemyY[1]); } } SDL_Flip(screen); printf("Enemys drawn..."); } As you can see the SDL_Surface *enemy is an array. Which at the for loop it crashes, any one know why? Hope I was descriptive enough, if not just ask for more info. Thanks.
As for why it will crash, more than likely you are accesing an element out of bounds. You are always accessing enemy/EnemyX/EnemyY[1] - I think that should be enemy/EnemyX/EnemyY. (Note that you need to use the i variable not '1'). See if that fixes it.
Quote:
Original post by Anonymous Poster
...This is definatly a problem: "if( Enemy == 1 )" Enemy should be a pointer to an SDL_Surface, ...
Careful now! I almost made that same mistake, but realized if that were the case, it would not even compile (no conversion for SDL_Surface* to int defined). There are two variables, enemy and Enemy. Enemy is not the SDL_Surface array, but enemy is. [smile] I would definitly opt for more conventional names to avoid confusion DarkLord2.
Quote:
Original post by Drew_Benton Quote:
Original post by Anonymous Poster
...This is definatly a problem: "if( Enemy == 1 )" Enemy should be a pointer to an SDL_Surface, ...
Careful now! I almost made that same mistake, but realized if that were the case, it would not even compile (no conversion for SDL_Surface* to int defined). There are two variables, enemy and Enemy. Enemy is not the SDL_Surface array, but enemy is. [smile] I would definitly opt for more conventional names to avoid confusion DarkLord2.
Ya, 1 was in there because I was just seeing if it would crash, but no luck. Heres the whole page: http://dev-street.com/DarkEngine/map.h
EDIT: I took the SDL_Surface *enemy[100] out of the class, it doesn't crash but it doesn't draw the enemys ethier...
[Edited by - DarkLord2 on April 10, 2005 8:12:23 AM]
Quote:
Original post by Rob Loach
I'd recommend using the STL instead of normal arrays. Here's a good resource on the matter. If you don't need random access for the enemies, you could use a linked list instead.
If you could, can you give me an example of how I would use that with SDL_Surface?
Quote:
Original post by DarkLord2 Quote:
Original post by Rob Loach
I'd recommend using the STL instead of normal arrays. Here's a good resource on the matter. If you don't need random access for the enemies, you could use a linked list instead.
If you could, can you give me an example of how I would use that with SDL_Surface?
std::vector<CEnemy*> Enemies;void DrawEnemies(){ for(std::vector<CEnemy*>::iterator pos = Enemies.begin(); pos != Enemies.end(); ++pos) { printf("Drawing image..\n"); (*pos)->Draw(); printf("Enemys drawn..."); }}void AddEnemy(){ Enemies.push_back(new CEnemy(/* attributes */));}Of course, it would help to understand the STL before using it. Load up a new project and play around with it.
Also, don't flip your screen after every image you draw. Call it once after you've finished drawing every image on the screen. Do this once every frame.
I'm messing with this for you [smile] . I've found a few issues, but I'm still going through the code. It'd be really helpful if you could upload all the .bmp's for me.
One problem you haven't addressed is the game loop. The game isn't crashing really. There's no loop, so things are rendered and the window goes away immediately. Anyways, please up those images and I'll be able to help more.
Update
The crash is happening because of this:
Remember that you start iterating through an array at 0, not 1. NumOfEnemys should be defined somewhere as 99, and lose the + 1.
[Edited by - Rhaal on April 10, 2005 10:26:03 AM]
One problem you haven't addressed is the game loop. The game isn't crashing really. There's no loop, so things are rendered and the window goes away immediately. Anyways, please up those images and I'll be able to help more.
images/enemy.bmpimages/background.bmpimages/block.bmpUpdate
The crash is happening because of this:
for( int i = 0; i < NumOfEnemys + 1; i++ )Remember that you start iterating through an array at 0, not 1. NumOfEnemys should be defined somewhere as 99, and lose the + 1.
[Edited by - Rhaal on April 10, 2005 10:26:03 AM]
Ok, I believe I've figured most of it out. As mentioned before, this isn't the best design so it was a little rough figuring out how you wanted things to work [smile].
Ok problem 1 was mentioned above so I wont go into it too much. Just remember, arrays start counting at 0, not 1. NumOfEnemies should be 99 in your case. You were going to 101 == buffer overflow == CRASH. I put this in the constructor of CMap.
Your enemies aren't rendering because you never gave values to your EnemyX and EnemyY arrays. Your map doesn't know WHERE to draw them. Actually, it drew them all at 0,0, stacking them, but you just saw a black square. I added this to the start of InitImages():
This isn't very clean or nice, because you probably want each enemy at a different area. What this does is increase x and y by the enemy's width and height. All you're going to see is a few enemies running diagnolly down the screen (depending on the enemy.bmp size, mine was small);
Now look at your DrawScene() function. Your logic in the if statement to draw Enemy's is slightly flawed. In C++, if evaluates to an integer. As Drew said, there's no conversion for SDL_Surface* to int so you can't do :
SDL_Surface* cannot evaluate to int, so Enemy cannot "equal 1". An SDL_Surface* can point to NULL, however. I changed your statement to:
This says "if the surface at Emeny is not (!) NULL"
Lastly, you need a game loop or everything will draw once and exit. Because of this you need to use and SDL_Event structure to handle input and get out of the loop. Below is the main.cpp file I used to test with and your map.h file with my changes. I've commented where I had to do workarounds. Hope it helps!
If you come across trouble I'll be glad to point things out [smile].
Oh yeah, in your map class I see your implementation is in the header file itself. Because of this, you need to use std::ifstream, not "using namespace std;". If you use a namespace in the header file, any file that includes that headerfile is stuck with the namespace. True, std is not going to get you in trouble, but it's good practice.
Ok problem 1 was mentioned above so I wont go into it too much. Just remember, arrays start counting at 0, not 1. NumOfEnemies should be 99 in your case. You were going to 101 == buffer overflow == CRASH. I put this in the constructor of CMap.
CMap() { NumOfEnemys = 99; }Your enemies aren't rendering because you never gave values to your EnemyX and EnemyY arrays. Your map doesn't know WHERE to draw them. Actually, it drew them all at 0,0, stacking them, but you just saw a black square. I added this to the start of InitImages():
int xstart=0;int ystart=0;for( int i = 0; i < NumOfEnemys; i++ ){ enemy = SDL_LoadBMP("images/enemy.bmp");}for( int i = 0; i <= NumOfEnemys; i++){ xstart += enemy[1]->w; ystart += enemy[1]->h; EnemyX = xstart; EnemyY = ystart;}This isn't very clean or nice, because you probably want each enemy at a different area. What this does is increase x and y by the enemy's width and height. All you're going to see is a few enemies running diagnolly down the screen (depending on the enemy.bmp size, mine was small);
Now look at your DrawScene() function. Your logic in the if statement to draw Enemy's is slightly flawed. In C++, if evaluates to an integer. As Drew said, there's no conversion for SDL_Surface* to int so you can't do :
if( Enemy == 1 )SDL_Surface* cannot evaluate to int, so Enemy cannot "equal 1". An SDL_Surface* can point to NULL, however. I changed your statement to:
if(!(Enemy == NULL) )This says "if the surface at Emeny is not (!) NULL"
Lastly, you need a game loop or everything will draw once and exit. Because of this you need to use and SDL_Event structure to handle input and get out of the loop. Below is the main.cpp file I used to test with and your map.h file with my changes. I've commented where I had to do workarounds. Hope it helps!
//map.h#ifndef CMAP_H#define CMAP_H#include <fstream>#include <SDL/SDL.h>#include "lx.h"class CMap{public: CMap() { NumOfEnemys = 99; } // 99 because it's 0-99, not 1-100. //~CMap(); int InitImages(); void DrawIMG(SDL_Surface *img, int x, int y); void DrawIMG(SDL_Surface *img, int x, int y, int w, int h, int x2, int y2); void DrawBG(); void DrawScene(); void GetMapData( char filename[] ); void CheckWalking(); //Map size int MapX, MapY; int NumOfEnemys; int EnemyX[100]; int EnemyY[100]; int Enemy[100]; SDL_Surface *enemy[100]; ////Enemys //int Enemy1X, Enemy1Y, Enemy2X, Enemy2Y; //int Enemy1, Enemy2; ////Health Stuff //int Health1X, Health1Y, Health1Ammount, Health2X, Health2Y, Health2Ammount; //int Health1, Health2;};// These should really be elsewhere or the user of your// CMap class will have to know about them and declare// them with extern whenever they want to use them.//Define the screen imagesSDL_Surface *sfBackground;SDL_Surface *sfPlayer;SDL_Surface *sfScreen;SDL_Surface *sfTest;// I don't know what this is or does.//Define the images//const char *Background;//Start pointsint PlayerXPos = 0, PlayerYPos = 0;// You don't need to re-declare SDL_BlitSurface().//int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);int CMap::InitImages(){ // New stuff, dirty workaround again :/ int xstart=0; int ystart=0; for( int i = 0; i < NumOfEnemys; i++ ) { enemy = SDL_LoadBMP("images/enemy.bmp"); } for( int i = 0; i <= NumOfEnemys; i++) { xstart += enemy[1]->w; ystart += enemy[1]->h; EnemyX = xstart; EnemyY = ystart; } // End new stuff //health1 = SDL_LoadBMP("images/health.bmp"); //health2 = SDL_LoadBMP("images/health.bmp"); //enemy1 = SDL_LoadBMP("images/enemy.bmp"); //enemy2 = SDL_LoadBMP("images/enemy.bmp"); sfBackground = SDL_LoadBMP("images/background.bmp"); sfPlayer = SDL_LoadBMP("images/block.bmp"); //health = SDL_LoadBMP("health.bmp"); return 0;}void CMap::DrawIMG(SDL_Surface *img, int x, int y){ SDL_Rect dest; dest.x = x; dest.y = y; SDL_BlitSurface(img, NULL, sfScreen, &dest);}void CMap::DrawIMG(SDL_Surface *img, int x, int y, int w, int h, int x2, int y2){ SDL_Rect dest; dest.x = x; dest.y = y; SDL_Rect dest2; dest2.x = x2; dest2.y = y2; dest2.w = w; dest2.h = h; SDL_BlitSurface(img, &dest2, sfScreen, &dest);}void CMap::DrawBG(){ DrawIMG(sfBackground, 0, 0);}void CMap::DrawScene(){ DrawIMG(sfBackground, PlayerXPos, PlayerYPos, 32, 32, PlayerXPos, PlayerYPos); DrawIMG(sfPlayer, PlayerXPos, PlayerYPos); printf("Drawing enemys...\n"); for( int i = 0; i < NumOfEnemys; i++ ) { printf("Drawing image..\n"); if(!(Enemy == NULL) ) { DrawIMG(enemy, EnemyX, EnemyY); } } SDL_Flip(sfScreen); printf("Enemys drawn...");}void CMap::GetMapData( char filename[] ){ std::ifstream MapFile(filename); int mouse; while(!MapFile.eof()) { //MapFile.get(mapdata); MapFile >> MapX >> MapY >> mouse >> NumOfEnemys;//Enemy1X >> Enemy1Y >> Enemy2X >> Enemy2Y >> Health1X >> Health1Y >> Health1Ammount; for( int i = 0; i < NumOfEnemys + 1; i++ ) { MapFile >> EnemyX; MapFile >> EnemyY; MapFile >> Enemy; } } printf("Map file loaded. Using %s.\n", filename); printf("Number of enemys: %d\n", NumOfEnemys); for( int i = 0; i < NumOfEnemys; i++ ) { printf("X of Enemy %d: %d\n", i, EnemyX); printf("Y of Enemy %d: %d\n", i, EnemyY); printf("Enemy %d is ", i); if( Enemy == 1 ) { printf("alive.\n\n"); } else { printf("dead.\n\n"); } } if( mouse == 0 ) { SDL_ShowCursor(0); } MapFile.close();}void CMap::CheckWalking(){ for( int i = 0; i < NumOfEnemys; i++ ) { if( (PlayerXPos < EnemyX) && (PlayerYPos < EnemyY) && (Enemy == 1) ) { Enemy = 0; printf("Hit an enemy.\n"); } }}#endif//main.cpp#include <iostream>#include <SDL/SDL.h>#include "map.h"using namespace std;#pragma comment(lib, "SDL.lib")#pragma comment(lib, "SDLmain.lib")#pragma comment(lib, "SDL_TTF.lib")// SDL Event structure for event handling.SDL_Event gEvent;// These are in map.h but shouldn't be. This is a dirty workaround (extern).extern SDL_Surface *sfBackground;extern SDL_Surface *sfPlayer;extern SDL_Surface *sfScreen;extern SDL_Surface *sfTest;// A flag to determine if the game is running.bool gRunning;int main (int argc, char** argv){ // Create a test map. CMap TestMap; sfTest = SDL_LoadBMP("windowsm.bmp"); // Initialize SDL. SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); // Set up the main screen sfScreen = SDL_SetVideoMode(800, 600, 24, SDL_HWSURFACE |SDL_DOUBLEBUF); // somethin' TestMap.InitImages(); // Enter the game loop. gRunning = true; while(gRunning) { // Fill the SDL event structure if(SDL_PollEvent(&gEvent)) { // Handle user manually closing the window if(gEvent.type == SDL_QUIT) { gRunning = false; } else { TestMap.DrawBG(); TestMap.DrawIMG(sfTest, 10, 10); TestMap.DrawScene(); } } } // Game isn't running anymore. Clean up time. SDL_FreeSurface(sfScreen); SDL_FreeSurface(sfBackground); SDL_FreeSurface(sfPlayer); SDL_FreeSurface(sfTest); return 0;}If you come across trouble I'll be glad to point things out [smile].
Oh yeah, in your map class I see your implementation is in the header file itself. Because of this, you need to use std::ifstream, not "using namespace std;". If you use a namespace in the header file, any file that includes that headerfile is stuck with the namespace. True, std is not going to get you in trouble, but it's good practice.
Wow, you guys are awesome. I got it working, thanks to all of you.
Thanks allot.
-Dark
EDIT: I don't really understand this:
Could you explain it? I kinda see what it does, but why is it needed? The EnemyX and Y arrays are set when it reads the data from the textfile(void CMap::GetMapData( char filename[] ))
Thanks allot.
-Dark
EDIT: I don't really understand this:
for( int i = 0; i <= NumOfEnemys; i++) { xstart += enemy[1]->w; ystart += enemy[1]->h; EnemyX = xstart; EnemyY = ystart; }Could you explain it? I kinda see what it does, but why is it needed? The EnemyX and Y arrays are set when it reads the data from the textfile(void CMap::GetMapData( char filename[] ))
Ok well what it does is loop through as many times as there are number of enemies. I'm sure you understand that part. One thing that's different is that you were just using "less than" instead of "less than or equal to" (<=). Without the equal part, you wouldn't get your last enemy.
xstart and ystart are 2 variables I created to hold an x,y position. They start at 0, and increase by the enemy surface's height and width each time through the loop.
Obviously, you want to set up your own on a case by case basis something like:
Here's what that snippet does in English:
I suggest re-reading some material on C++ loops, and yes, learn the STL. You don't have to learn how to create your own templates, that's daunting to me, but using things like std::list and std::vector will make things easier on you.
Edit: I should note the following
You can get an SDL_Surface's width and height via ->w and ->h . I picked [1] as an semi-arbitrary element in your enemy[] array. This is because there should at least be one enemy in the array. That number doesn't need to increase as the loop iterates, it's just for reference. Keep in mind, this is if all your enemies are the same size. Remember, there are design issues at hand here. In hindsight, I made a minor error. enemy[0] should have been used, not enemy[1]. As you can see, the arrays starting at [0] get me sometimes too! [wink]
xstart and ystart are 2 variables I created to hold an x,y position. They start at 0, and increase by the enemy surface's height and width each time through the loop.
Obviously, you want to set up your own on a case by case basis something like:
EnemyX[1] = 5;EnemyY[1] = 10;EnemyX[2] = 50;EnemyY[2] = 30;...Here's what that snippet does in English:
As many times as there are numbers of enemies. Increase the temporary x variable by the enemy's width. Increase the temporary y variable by the enemy's height. Set the EnemyX variable at this iteration to the temporary x variable. Set the EnemyY variable at this iteration to the temporary y variable.I suggest re-reading some material on C++ loops, and yes, learn the STL. You don't have to learn how to create your own templates, that's daunting to me, but using things like std::list and std::vector will make things easier on you.
Edit: I should note the following
xstart += enemy[1]->w;ystart += enemy[1]->h;You can get an SDL_Surface's width and height via ->w and ->h . I picked [1] as an semi-arbitrary element in your enemy[] array. This is because there should at least be one enemy in the array. That number doesn't need to increase as the loop iterates, it's just for reference. Keep in mind, this is if all your enemies are the same size. Remember, there are design issues at hand here. In hindsight, I made a minor error. enemy[0] should have been used, not enemy[1]. As you can see, the arrays starting at [0] get me sometimes too! [wink]
Ah.. Thats pretty handy, thanks alot, one more question if you don't mind. I'm working a tile system and since SDL_LoadBMP needs a const char * for it to load it, but when I make a var const char * and run this: MapFile >> Tile; it gives me an error, so is there any way to change a char to a const char?
Quote:
Original post by Rhaal
I've only got a minute on the computer atm so if this isn't what you're asking, forgive me [smile].int f(const char* c){ //bah...}// elsewhere...char* RegularChar;f( static_cast<const char*>(RegularChar) );
Again, I could be wrong about this. If so, I'll edit my post later.
Makes sence, but would c be the new char or f?
[Edited by - DarkLord2 on April 10, 2005 8:04:15 PM]
Well f is the function that needs a const char*. Within that function's scope you use the parameter c. If this is confusing to you, you have some C++ basics to work out such as functions and scope.
Don't mess around with char* when you can use std::string. Just #include and do this.
c_str() is a function that will return a C style string, which is what you need in SDL_LoadBMP().
Don't mess around with char* when you can use std::string. Just #include
std::string SwordFile = "sword.bmp";SDL_LoadBMP(SwordFile.c_str());c_str() is a function that will return a C style string, which is what you need in SDL_LoadBMP().
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement