Array of SDL_Surface for Space Invaders Clone

Started by
6 comments, last by Zahlman 14 years, 10 months ago
Hey Everyone, I'm working on my first game (a Space Invaders-ish clone) and am running into a problem while attempting to draw a set of blocks (representing enemies for now). Unfortunately I'm at work now so I don't have my source-code but effectively, I created a 5x8 array of SDL_Surfaces like so...

SDL_Surface blockArray[5][8] = {{NULL}};


then, later in the code in a class I created called 'blocks' I have a constructor that loops through the array and sets each surface an already optimized image called blockjpg

blockArray[blockY][blockX] = blockjpg;

blockY and blockX being counters that are incremented in nested For loops. I think this is where my problem is, but I could be way off here. After that, I have a function called blocks::drawblocks() that basically (as a test for now) just attempted to draw the first 5 blocks in the array to static locations on my screen that I manually inputted.

apply_surface(40, 80, blockArray[0][0], screen);
...
...
so on and so forth

I could be doing this COMPLETELY wrong but I'll try to get the actual code up later. Any help would be most appreciated.
Advertisement
It's difficult to say for sure without seeing the rest of your code, but remember that SDL_BlitSurface takes two SDL_Surface pointers as arguments not two SDL_Surface objects. As a matter of fact, I think all SDL functions use SDL_Surface pointers instead of SDL_Surface objects.

Also of note, the struct SDL_Surface contains pointer data in it. If I am wrong somebody correct me, but I believe this means that if you are assigning blockjpg to a location in your array and then change the image of blockjpg, the image held in your array will also change.
Quote:Original post by Zael
It's difficult to say for sure without seeing the rest of your code, but remember that SDL_BlitSurface takes two SDL_Surface pointers as arguments not two SDL_Surface objects. As a matter of fact, I think all SDL functions use SDL_Surface pointers instead of SDL_Surface objects.

Also of note, the struct SDL_Surface contains pointer data in it. If I am wrong somebody correct me, but I believe this means that if you are assigning blockjpg to a location in your array and then change the image of blockjpg, the image held in your array will also change.



I'll get the code up as soon as I can. The blockjpg and screen are actually SDL_Surface*. This is the first time I have attempted to use an array of SDL_Surface's so I expected some issues. Thanks for the followup.
Zael you led me right to it! Turns out I declared the array as SDL_Surface objects and NOT pointers. Once I fixed that everything worked out. I even got my draw() function to work well. It definitely isn't pretty but with a nice clean loop it draws the block grid on the screen.

Photobucket

I'm really making some progress now. Thanks for the help :)
Alrighty, ran into another problem. Now that I can draw my array of surfaces I want to test removing individual blocks from the screen. To do this I basically construct an equally sized array of integers, and set all values to 1.

blocks::blocks(){	for(int blockY = 0; blockY < 5; blockY++)	{		for(int blockX = 0; blockX < 8; blockX++)		{			blocksAlive[blockY][blockX] = 1;		}	}	for(int blockY = 0; blockY < 5; blockY++)	{		for(int blockX = 0; blockX < 8; blockX++)		{			blocksArray[blockY][blockX] = block;		}	}}



Once this is done, during the draw function I loop through this array and check to see if any values == 0. If they do, don't draw that block. But for some reason this is only working with elements in the [0][x] section of the array. Any other value of Y and it fails.

void blocks::drawblocks(){	for(int drawY = 0; drawY < 5; drawY++)	{		for(int drawX = 0; drawX < 8; drawX++)		{			if(blocksAlive[drawY][drawX] == 0)			{				continue;			}		switch(drawY)		{		case 0:		apply_surface(((SCREEN_WIDTH / 8) - (BLOCK_WIDTH / 2)) * (drawX + 1), 40, blocksArray[drawY][drawX], screen, NULL);		case 1:		apply_surface(((SCREEN_WIDTH / 8) - (BLOCK_WIDTH / 2)) * (drawX + 1), 80, blocksArray[drawY][drawX], screen, NULL);		case 2:		apply_surface(((SCREEN_WIDTH / 8) - (BLOCK_WIDTH / 2)) * (drawX + 1), 120, blocksArray[drawY][drawX], screen, NULL);		case 3:		apply_surface(((SCREEN_WIDTH / 8) - (BLOCK_WIDTH / 2)) * (drawX + 1), 160, blocksArray[drawY][drawX], screen, NULL);		case 4:		apply_surface(((SCREEN_WIDTH / 8) - (BLOCK_WIDTH / 2)) * (drawX + 1), 200, blocksArray[drawY][drawX], screen, NULL);		}		}	}}



So basically, I can only affect the top row of blocks with this method. I must be missing something minor here as the top row works exactly as intended.
Still stuck on this one. /bump for some help
SOLVED No breaks in the switch statement D'OH!
1) Regarding the original question, next time say what the problem is. If you have a compiler error, post the error(s). If you have a linker error, similarly. If it just plain doesn't do what you expected, describe (i) what you expected and (ii) what actually happened.

2) Of course you need breaks in the switch statement for that approach to work. But there is no reason to use a switch statement in the first place. See how you're already doing some arithmetic based on drawX to find the X drawing position? That's smart. Do the same thing for the Y coordinate.

3) The array of flags and the array of block image pointers are redundant. You can either:

a) Just keep the array of flags, and hard-code the drawing loop to use the one surface pointer; or

b) Just keep the array of pointers, and when a block is destroyed, set the corresponding pointer to NULL; and in the drawing loop, skip drawing when you find a NULL pointer.

4) If you decide to keep the flags, use either booleans or an enumeration, instead of integers. In C++, we have a real boolean type, named "bool", so you don't have to think about things like "0 means false and everything else means true". You can actually use the names 'true' and 'false', and you can use the state of a boolean variable directly to control a loop/if statement instead of comparing it to anything.

I show code below with the "null pointer for skipped block" approach. This is flexible; it easily lets you use multiple block images, by just setting the pointers. (With an enumeration, you would have to use the enumeration value to look up the corresponding block. And with a boolean, you couldn't do it at all.)

void blocks::drawblocks(){	const int HORIZONTAL_SPACING = ((SCREEN_WIDTH / 8) - (BLOCK_WIDTH / 2));	const int VERTICAL_SPACING = 40;	for(int drawY = 0; drawY < 5; drawY++)	{		for(int drawX = 0; drawX < 8; drawX++)		{			SDL_Surface* block = blocksArray[drawY][drawX];			// You can use pointers directly for if statements, too;			// the condition is true when the pointer is not NULL.			if (block)			{				apply_surface(					HORIZONTAL_SPACING * (drawX + 1),					VERTICAL_SPACING * (drawY + 1),					block, screen, NULL				);			}		}	}}


Also keep in mind for when you're removing blocks, that you need to clear the screen before you start this drawing process. Otherwise, the old images of removed blocks will remain on the 'screen' surface.

This topic is closed to new replies.

Advertisement