Original Post

I’ve decided that since I have absolutely no experience whatsoever playing RPGs, that I am not a good candidate of programming one, so instead, I’m going to work on a fighting game (while I also have no experience playing a fighting game, I’d figure it’d be a lot easier programming one than an RPG.) So here’s my latest brainchild: Insect Combat. Right now, it’s just a warning screen and a title screen. The only two characters I’ve thought of so far are Gi-Ant and Behe-Moth. Any other punny names you guys can think of would also be appreciated.

Attachments:
399 Replies

By the way, I took a peek at your code, and while I’m not familiar with VB coding specifially (or all that familiar with C, for that matter), it seems like your main() function is just gargantuan and handles pretty much every single screen. Aren’t you going to run out of memory, keeping it all in that one single humongous function? I’m also surprised you have any oversight on the entire program at all this way!

It would be better to split it up into several more specific functions (like for each different game screen/state) and make the appropriate calls when switching to a different one. That way, you have a clear overview on you’re in the TitleScreen(), or the CharacterSelect(), or the MainGame()… The code is grouped more logically and you can be 100% sure that it’s not somehow performing actions from a different game mode. It also frees up some CPU as you don’t have to check what state the game is in every frame. This entire StartGame/GotoStart value switching and checking business would also disappear completely, which would certainly simplify the code in general.

There’s also a lot of switch…case statements where you then do a check for 1, 2, 3 etc. with code that looks *mostly* the same. You could completely avoid even needing a lot of these switch…cases and greatly simplify and shorten the code if you stash all the variables like NEWGIANTFINALCHAR into a new array and reference from that array.
The effect would be that a lot of these sets of 8 repeated statements, each occupying 4 lines, would be replaced by a single statement with 6-7 lines. Greatly shortens your code and prevents code duplication (which is a good general coding guideline in general, since it makes changing things so much easier).

switch (fighter) {
  case 1:
    fightery=70;
    copymem((void*)CharSeg2, (void*)NEWGIANTFINALCHAR, 512*16);
    copymem((void*)BGMap(2), (void*)NEWGIANTFINALMAP, 512*16);	
  break;

  case 2:
    copymem((void*)CharSeg2, (void*)BEHEMOTHCHAR67, 512*16);
    copymem((void*)BGMap(2), (void*)BEHEMOTHMAP67, 512*16);	
  break;
  
  //And then for all 8 cases + default...
}

//And then pretty much an identical looking block of duplicated code comes later, purely for handling the opponent's fighter. (Easily solved by putting all of that in a new function dedicated to the selection screen, then calling that twice: once for the player, once for the opponent.)

turns into something like this (pseudocode because I don’t know enough C to properly do arrays):

//Arrays containing the correct references to the right chars and maps
char fighterchars[] = {NEWGIANTFINALCHAR, BEHEMOTHCHAR67, NEWRUMBLEBEECHAR, NEWMELEEDYBUGCHAR, SUPERFLYCHARNEW, NEWKILLIPEDECHAR, PANZERCHAR, MANTISCHAR2};
map fightermaps[] = {NEWGIANTFINALMAP, BEHEMOTHMAP67, ...}; //Same deal as above but for the maps


...
//At the player select bit:


//Handle the special cases (1 and 8)
if (fighter == 1) { fightery = 70; }
else if (fighter == 8) { ten = 0; fightery = 80; }

//Handle the player's fighter.
copymem((void*)CharSeg2, (void*)fighterchars[fighter-1], 512*16);
copymem((void*)BGMap(2), (void*)fightermaps[fighter-1], 512*16);

//Done, nothing more needed

If I try to break it up, it just does the intro part over and over again and doesn’t go to the title screen part LIKE I TELL IT TO. I cleaned up the code up until the title screen part ends. Why won’t it go to the title sequence? Also, I need a part called int main(). If I don’t, there’s an error message telling me I need one in there. So that’s the deal with the main part.

Yeah, main() is necessary, that makes total sense. What I meant is that from that main() you’re then free to call other functions and separate your code that way. main() itself usually stays pretty small. Looks like that’s how you’ve done it now. 🙂

I’m trying to figure out why your code doesn’t work now, but there’s a lot of variables with unclear names or purposes. I’m going to have to read through the code bit by bit to try and understand the general flow before I can really help with that. I’m going to have questions, and I’m also going to point out things, which hopefully make the code much more compact and easier to understand over time.

I can tell you one thing, though. You definitely seem to be using more variables than you need, and checking certain specific states more often than you really need. This really adds up to the clutter.

What are GoToStart and StartGame for? (Keep reading before replying 🙂 )
I see you use these variables a lot, and they seem to have a lot of values (StartGame even goes as high as 6!), but I’m not sure why. What does each of the values (0-6) represent? Why is it 4 at the start?

I see that you generally use it to break out of specific loops. Here’s a tip: you can use break; not just to quit out of switch..case statements, but also to quit out of loops! Thanks to this you suddenly don’t need a lot of the variables you’re using.

For example, if I look at a bit of code in your intro (from which I understand it’s supposed to make the game wait until you press start), this:

while((GoToStart==0) && (StartGame>3)) {
  if((vbReadPad()&K_STA) && (StartGame==4)) {
    StartGame=6;
    FadeOut();
  }
  
  if((!(vbReadPad()&K_STA)) && (StartGame==6)) {
    StartGame=3;
  }
}

will turn into this:

while (GoToStart==0) {
  if((vbReadPad()&K_STA)) {
    FadeOut();
    break; //Start was pressed, quit out of it
  }
}

…Or you could even bring it down to its very core and just make it wait and do nothing for as long as the “start pressed” condition has not been met:

while(GoToStart==0 !vbReadPad()&K_STA) { }
FadeOut(); //It's been pressed, so continue as normal.

That’s going from 8 lines to 2 lines for code that essentially still does the same thing. And I’m sure even (GoToStart==0) can be removed from the equation here, as I’ll show in the next post. 🙂

  • This reply was modified 10 years ago by DaVince.

So sorry for not having reached the relevant bit where your code goes wrong yet. It’s good to simplify everything else about the program before really proceeding, I think, as simplifying the code base will probably resolve the issue altogether. 😉

Next up, you do this a lot:

while(GoToStart==0 && some condition...) {
  //bunch of code
}
if (GoToStart==0 && some other condition...) {
  //Some other code
}
while(GoToStart==0 && yet more conditions...) {
  //Yet more code
}

All these GoToStart==0 conditions certainly add up, both to the amount of stuff the VB has to do, the final machine code generated, and how complex the source code itself looks.

My tip: check (GoToStart==0) only once. You can usually group a whole bunch of those together. Grouping it all also makes it more recognizable as that entire list of conditions being a part of “when GoToStart is zero”.)

if (GoToStart==0) {
  //Tab everything here; now it's clear from the raised indentation that the following is all related to (GoToStart==0).
  while(some condition) {
    //bunch of code
  }
  if (some other condition) {
    //some other code
  }
  while(yet more conditions) {
    //yet more code
  }
}

And if you want to be done with that entire block early on, you can use the continue; statement to exit out of the large if statement (it has the same effect as break; in loops and switch..cases).

Oh, I also recommend you do this:

int main() {
  intropart();
  while (true) {
    //while(true) is an infinite loop. Whenever you return; out of a function
    //that was called from this loop, the game will just continue running the
    //code in this loop and thus end up back at the title screen.
    switch(game_state) {
      default: case STATE_TITLE_SCREEN:
        titlescreenpart();
        break;
      case STATE_STARTNEWGAME:
        charselect();
        prefight();
        fightscreen();
        break;
      case STATE_OPTIONS_SCREEN:
        optionsscreen();
        break;
      case STATE_CREDITS_SCREEN:
        creditsscreen();
        break;
      case STATE_SOMETHING_ELSE:
        //do that
        break;
    }
  }
}

That’ll ensure several things:
– Whenever you completely exit out of any functions, it’ll just return to the main screen.
– You’ll have a game_state variable from which you can exactly tell where the game is now.
– The main game/screen switching logic is in one place, and one place only. That’s the only place you’ll be able to mess up going to the wrong screen from there on.
– It’ll clean up your RAM a lot: since you exit out of functions, the game can now unload those functions from RAM! That gives you better overall performance.

You’ll have to declare the appropriate variables, of course (game_state, and all those STATE_ variables, which can just have unique int numbers that are useful for you, the coder, to understand what state it’s in).

EDIT:
Oh! And by using functions, you can start moving a lot of the global variables into the functions they are used in. This saves some RAM you can use for other purposes too. 😉

  • This reply was modified 10 years ago by DaVince.

If I try to break it up, it just does the intro part over and over again and doesn’t go to the title screen part LIKE I TELL IT TO.

I reached that part of the code! Looks like it’s a typo that ensures that the value of openingpart never increases.

if (CreditsScrollingY<-222)

should be

if (CreditsScrollingY<=222)

That said, I think it's a better idea to break; out of that loop rather than calling titlescreenpart(); once it reaches 3. Because right now, all the code you have below the looping intro (paused=0; and onwards) simply won't get a chance to run. And you run titlescreenpart(); at the very bottom of the function already anyway.

Edit: by the way, the game's more fun now that the action is a lot faster! I do notice that my attack is ignored sometimes, though - I guess that's not on purpose at this stage?

Edit 2: I found that as soon as I'm picked up by the enemy, I instinctively start thrashing the buttons in the hope that it'll release me. You could add an element of that succeeding every once in a while, perhaps. :-D

I did what you told me to. It ended up running really fast on Mednafen, but a lot slower on a real VB. I don’t know why that is, but since I want to optimize the code for use on a real VB, I’ll leave it the way it is. Anyway, I took out the options menu since all it did was display the credits. It took me a couple of hours, but I think I did everything right. Let me know.

It ended up running really fast on Mednafen, but a lot slower on a real VB. I don’t know why that is, but since I want to optimize the code for use on a real VB, I’ll leave it the way it is.

So is it still faster in general, or did something happen that actually made the game perform worse than before on a VB? That sounds pretty unexpected, considering you’re giving the system less to do… Well, I don’t know what changed exactly you made either that made it act that way though.

I have no idea how VB handles this, but with PCs on pretty much any other system, a game will push out as many frames per second as it can muster. That is, if the hardware has enough power to display a game at 400 FPS, it will show it at 400 FPS. Developers normally have to put code on their stuff that limits the frame rate so it runs at the correct speed.

An emulator normally limits the performance to emulate the maximum speed of the actual original console, but I guess Mednafen has an inaccuracy there.

Will take a peek at your edited code tomorrow. (Speaking of which; your source code is not complete or compilable until you include *all* the source files, that is, the .h files and whatever resources the game relies on.)

I added to the Insecticide website a zip file containing (hopefully) all the .h files I use to get the game running and a link to the Soviet sound engine that the game uses. If you download the stuff and can’t get it working because I forgot a file, please let me know. Also, TODAY’S (10/17) .zip file of the game and code is needed because I erased some of the .h files no longer needed that were in yesterday’s version.

Looks like header files are still missing… I also had to rename vb\notes.h to just notes.h.

Edit: also, about this in your main():

while (game_state>-1) {

Actually, you can just keep that as while(true). There isn’t a single moment in the game you’d ever want to completely quit out of it, right? Heck, I’m not even sure how the VB would react to that! Not to mention your game_state never even becomes -1, so (game_state>-1) is already always equal to true. 😉

  • This reply was modified 10 years ago by DaVince.

I tried to type in “while(true)”, but it didn’t like it. Here are some more .h files along with another modded .c and .vb file. I got rid of the instrument thing because I wasn’t using it. (i.e. PIANO, etc.)

Great, now only superflycharnew.h is still missing. 🙂

I tried to type in “while(true)”, but it didn’t like it.

Oh. Hm. Wonder if that’s C or compiler related (I’m not too familiar with C after all).
Well, the following infinite loop will work (since I saw it used by the music player example):

for (;;) {

Here is that.

I noticed in trying to fix the code, that there was a break; missing in main(), so I fixed that. Then I had the trouble of the game making weird sounds that sounded like the music when the game was paused. I finally got that resolved. But the problem of it being faster on Mednafen than on real hardware is still there. I got the speed difference lessened, but I don’t know how, but it’s still there.

I hope you don’t mind if I make some additions/changes to the code (mainly cleanup and separating things into functions, and adding many helpful notes for you) and then upload the new file.

Edit: by the way, it seems like the game moves at such an inconsistent pace because the frames aren’t limited, causing them to move at the max possible speed. That would explain why it’s too fast sometimes, but it doesn’t explain the slowness in some situations. Especially the standard “wait for drawing to finish” code from the demo games makes the intro slow down to a crawl.

The only possible clue I have for that is that the VB is getting worked too hard, but in that case it should’ve been slow regardless… so that’s probably not it.

  • This reply was modified 10 years ago by DaVince.
  • This reply was modified 10 years ago by DaVince.
  • This reply was modified 10 years ago by DaVince.

Oh, I know why it happened. It’s because you told the game to be that slow. Instead of locking the frame rate, you tell the game to do something 16 times and then progress a single frame.

You know… That’s really unpredictable. You really won’t know how much time the VB (or emulator!) has in order to do that. The more you do in a loop, the slower that gets. It’ll be too fast, but you can’t really tell how much too fast. You’d have to make a guess at slowing it down that will change every time you touch the code.

So that’s why it’s a good idea to limit the frame rate. Rely on using vbWaitFrame(0); or WaitForVIP() to make the game forcibly wait until it’s time to display the next frame. You’ll get a solid 50 FPS (once you remove the code that does the unnecessary counting to 16 and stuff of course).

All right. I did it. I edited a bunch of code, and I left tons and tons of comments and information on what I did and why I did it.

To be honest, I think it would be so much better for you if you brush up on a few basic coding concepts. Things like:
– Functions and function arguments (http://www.learncpp.com/cpp-tutorial/14-a-first-look-at-functions/, http://www.learncpp.com/cpp-tutorial/71-function-parameters-and-arguments/)
– The importance of avoiding duplicate code (http://en.wikipedia.org/wiki/Duplicate_code)
– The usefulness of arrays (http://www.tutorialspoint.com/cprogramming/c_arrays.htm)
– Tips for naming variables (http://www.makinggoodsoftware.com/2009/05/04/71-tips-for-naming-variables/)
– Global and local variables (http://www.codingunit.com/c-tutorial-functions-and-global-local-variables)
– Why indentation is important (http://www.cs.arizona.edu/~mccann/indent_c.html#One)
– Separate your code! Instead of one huge function where everything happens, chop it up into pieces that do their own job. (http://en.wikipedia.org/wiki/Separation_of_concerns)
– Commenting your code (http://www.hongkiat.com/blog/source-code-comment-styling-tips/)
I’ve done this a few times to add little descriptive bits above the code of which it’s not immediately straightforward what it does. Helps people who see it for the first time a TON.

As well as:
– avoiding to check the same condition over and over. Check it once, nest the rest in there.
– How to prevent a loop from simply running as quickly and as much as it can. This is what causing almost *all* of the timing issues in your game (besides the bottlenecks).
This is common in game programming: you WANT to limit the amount of loops run to 50 per second. Luckily, the VB has vbWaitFrame() and WaitForVIP() to do that for you! (I used WaitForVIP() in the code)

It’s a lot of reading and learning, but it will help immensely. Plus you’re already halfway there – you’ve managed to write a working program. Even if that program is an unmanageable mess that breaks if you touch it too much. 😉

Next up, the code.

  • This reply was modified 10 years ago by DaVince.
  • This reply was modified 10 years ago by DaVince.
  • This reply was modified 10 years ago by DaVince.

I zipped up my version of the source code, along with a modified sounddat.h.

Do a ctrl+F for “DaVince note”. You’ll find a lot of results that I hope will be really helpful for you improving your coding skills! 😀

:vb: Notes of interest :vb:

The font never compiled/looked the way it should for me. (See attached screenshot.) (Edit: I was told it’s because the game is compiled with gccvb 1.0 and since I use VBDE with a newer gccvb it expects the font to be slightly different. So that’s that I guess.)

The timing of some things is off, but that’s because I completely fixed the timing in most screens. Except for the second character selection screen, because that’s a huge 250 line chunk of duplicated code (I’m not fixing things twice and there’s no point to having the same 250 lines twice in your source. Check my code comments to learn more on that!).

I hope none of this actually offends you in any way. I spent hours upon hours going through the source, thinking of any tips and helpful additions/changes I could make. In the end, this is all so you can become a better coder, so you can make a better program that’s easier for you to change and add things to in the future. Which means we get to see increasingly better versions of it more quickly. :thumpup: 😀

  • This reply was modified 10 years ago by DaVince.
  • This reply was modified 10 years ago by DaVince.

Thank you for all the tips and stuff about stuff I never knew about, especially WaitForVIP. But I have a problem, though: This new code won’t compile right. I tried compiling the code which you made for me, and I tried halfing the character select code, and I get the following messages.

Ah, the warnings are actually no big deal. They are there because we’re calling functions in main() that don’t even exist yet at that point (they are defined later in the code), so it’s warning and telling you it’s declaring them for you. You can actually fix that by defining them before int main, like this:

//This is what I'm talking about! The function "foo" is now declared properly and explicitly before main:
int foo(int arg);
void initgame();
void preintro();

//Then the main function comes
int main() {
  //Code that refers to foo, initgame, preintro...
}

//And then the *actual* function definitions.

int foo(int arg) {
  // code
  return 0;
}

void initgame() {
  //code here...
}

void preintro() {
  //You get the gist of it
}

Is it actually erroring out or not? Let’s find out once you get rid of the warnings. 🙂

 

Write a reply

You must be logged in to reply to this topic.