The mystery of the appearing enemy fighter

This is a discussion on The mystery of the appearing enemy fighter within the Game Programming forums, part of the General Programming Boards category; Hello to all, recently I have been working on a fairly complex game similar to the widely popular 1980's game ...

The mystery of the appearing enemy fighter

Hello to all, recently I have been working on a fairly complex game similar to the widely popular 1980's game "Space Invaders". Of course, I will deviate from this path and make it into a game that is clearly my own. Due to lack of creativity, and for the simplicity of the implementation, the movements and some graphics will be somewhat similar for the time being. Enough of my pointless babbling though, I need to get to what my question was. I had the code worked out, and everything was great. Then, when I tried to load in 30 enemy images for use later in the game, I noticed that, mysteriously, an enemy fighter had appeared without me ever blitting it onto the screen. I think that this problem also has to do with the mysterious "empty space" mystery also. It seems to go black occasionally, even though all my background images are never completely black. Originally I thought it was some kind of illegal memory access in my code, but it would've crashed with signal SIGSEGV if it was. Which leads me to believe it's my implementation somewhere in my code. I have no clue as to how the enemy fighter started appearing every time the "empty space" mystery occurs. I was hoping you would help me figure out what I'm doing wrong.

Here is the full source code, I commented out the enemy fighter parts for obvious reasons.

Your program is too long for me to dig through, but I imagine it's nothing more than a simple logical error. Have you tried debugging it? Putting breakpoints at the point something may go awry? Putting in asserts for things that should never happen?

And:

"Originally I thought it was some kind of illegal memory access in my code, but it would've crashed with signal SIGSEGV if it was"

is absolutely 100% wrong. SIGSEGV only occurs if the OS detects a massively illegal memory access (i.e. outside of the memory segments allocated to the program - hence the SEG and the word segfault), it doesn't stop you corrupting memory in any way and won't detect most things at all if they are small logical errors (like being one-off in the particular size, etc.). Don't think it does, and don't assume that because you don't get a SIGSEGV everything is alright.

You've written a program - now go debug it. What have you tried in terms of actual debugging?

- Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
- A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
- The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

After a quick look through, which is by no means accurate or conclusive, I just wanted to make sure your program even compiled properly...

Just from the screenshots it looks like the background image is actually changed to the "fighter" image. This is why you get a black frame with no stars, and the enemy fighter appears at 0,0 - your code is drawing what it thinks is the background but it has been handed the fighter image.

That would be where I would start to look - and probably that "linked list" implementation you have there. That would be my most likely culprit. But, as I say, I haven't time to debug other people's programs for them if they haven't even thought to debug / stick a printf in there somewhere.

Personally, I'd be sticking a "printf("Just printed the background, size %i, %i\n", surface->w, surface->h);" in there somewhere when I draw my background. I bet when the problem occurs that the surface drawn changes size because you're actually printing the fighter, not the background. That whole "offset" thing looks likely to be the cause of the breakage to me.

- Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
- A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
- The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

Your program is too long for me to dig through, but I imagine it's nothing more than a simple logical error. Have you tried debugging it? Putting breakpoints at the point something may go awry? Putting in asserts for things that should never happen?

And:

is absolutely 100% wrong. SIGSEGV only occurs if the OS detects a massively illegal memory access (i.e. outside of the memory segments allocated to the program - hence the SEG and the word segfault), it doesn't stop you corrupting memory in any way and won't detect most things at all if they are small logical errors (like being one-off in the particular size, etc.). Don't think it does, and don't assume that because you don't get a SIGSEGV everything is alright.

You've written a program - now go debug it. What have you tried in terms of actual debugging?

I didn't do much in terms of debugging, but after you posted I went through and looked at my code. One of the reasons I didn't think there was a SIGSEGV was because I thought SDL would handle it, since it usually does. Apparently, I shouldn't rely on it, I ran it through my Windows debugger when I was looking through my code and immediately discovered a segfault on line 327. At first I didn't understand why it would happen because the y coordinate was a proper variable and wasn't a trash value. Then I thought that maybe the node was removed and then my code tried to access that value again. I added a fprintf() to see if the node was removed or not. It was removed when it reached under 0 and then it was tested a second time causing the segfault. I added a break to the loop believing that would fix it :

I am just a beginner in C, so I don't understand the code. But this must take days to debug :|:|....

Now extend that to 1000s of lines of code for an OS kernel, where a debugger is almost impossible to be used, and all goes to hell because you failed to connect inline assembly correctly with everything else, and why? Because you forgot to declare a single register as used...
I spent a whole day( 24 hours ) in trying to solve this problem, and I was banging my head against the wall for making that foolish mistake.

I am just a beginner in C, so I don't understand the code. But this must take days to debug :|:|....

500 lines? Sorry, but this is really nothing. A quick single-step through with a debugger will find the problem for you in less than ten minutes. Fixing it might take a little longer. If you don't have such advanced tools available (yeah, right, debuggers are ten-a-penny nowadays and you're compiling with something, I guarantee it has a debugger too), then just single-stepping through the code by means of printing statements as you go so you can trace through what's it done.

In it's simplest form, this is just a "printf" of various variables at various stages, and thus showing what values variables hold as you jump between functions. It'll generate a ton of output but you can just skim most of it until you see where the problem hits. But with any of the decent debuggers, you'll find that problem quite quickly if you understand the code and can single-step it. When I was a kid, "debugging" meant running through things on paper using your head as the compiler/computer, and still you'd find this problem in under a day. Way under a day.

But this is also why, when we build larger programs, we modularise them. You really don't want to worry about whether "append_list" etc. in the above are correct when you're relying on them so much. So you would modularise them, put them into a source file of their own, and test and debug them as a separate program before you started using them in your own code. That way you don't have to worry if what you've done is cocked up the list implementation - you'll know which part of the program must be wrong and can concentrate your efforts on the module you know is wrong. Here, there's just a bunch of code in one long file, which makes things harder. You remember all that stuff you learned about header files and .c files etc.? This is why we use them. Personally I'd have "list.h" and "list.c" which contained all the things I needed to do with lists, and the main program would just include it. Bam. Dozens or hundreds of lines of code out of your main file that you know do nothing but lists and which you can test separately.

And then when everything is in nice little blocks, your usual debugging will be much simpler too. Oh, the list is giving the wrong item back? Okay. Probably can ignore EVERYTHING else in the whole program and just concentrate on debugging my list.

If you think this is bad, I'm writing a 2D isometric game that is nowhere near complete. It's over 150,000 lines of C, all written by me. There's so much code in there, that I don't even RECOGNISE it as my own code when I come back to it years later. And though I might have individual C files with several thousand lines of code, it's modularised so they are self-contained, and I don't attempt to dig into problems without a decent debugger.

- Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
- A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
- The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

I do not see 30 images. I see code that loads 3 images. Instead of using that ternary just do:

Code:

...
++offset;
if (offset >= MAX_SPACE_IMAGES)
{
offset = 0;
}
...
...

Also if you are running in debug mode you can certainly blow the bounds of an array. Memory has tons of extra 'space' in it between objects while in debug mode. I suspect if you run this in release mode it will seg fault.