Structuring a games code...

Started by
19 comments, last by d000hg 18 years, 8 months ago
I know what you mean. But the more you code, the better your structure will be. Take my word for it. In the mean time, here are a few tips to help you:

-When you get an idea, don't immediately sit down and code it. Look at Steven Spielberg. Did you know that for every scene he directs, he shoots from MULTIPLE camera angles to determine the best view for for the final cut? Not a surprise, but take his advice. Look at your problem from multiple angles and decide on an approach that will work best.

-Formalize your code. Give yourself a standard coding paradigm. Make yourself put that space after every parenthesis. Make yourself place a g_ before each global variable. This structure will propagate throughout your code and you will find that even your design will benefit from it.

-Read professional code like a book and learn from it. Yes, it is a bit overwhelming when you are trying to look through 400,000 lines, but get over it and just pick a spot and begin. For example, I opened up the quake source one day and chose a random document. It just happened to be one of the header files that redefined int to qint and float to qreal IIRC. I went searching online and found that the reason for this is to allow for compatibility across multiple platforms in the future. There we go - one more technique from the pros. Learn from them.

Best of luck.
....[size="1"]Brent Gunning
Advertisement
Some tips based in the source code you posted (sorry if I sound a bit harsh here and there, my intentions are to give you useful feedback, no flaming):

- break up the functions into sets of smaller functions with meaningful names. For example:
if (keys[SDLK_SPACE]){    if (shoot){        shoot = false;        shoottime=SDL_GetTicks();        for (int i=0;i<BULLET;i++){            if (barray.used==0){                            barray.x=player.px;                            barray.y=player.py;                            barray.radians=player.radians;                            barray.xv=cos(player.radians)*10;                            barray.yv=sin(player.radians)*10;                            barray.angle=player.angle;                            barray.time=SDL_GetTicks();                            barray.used = 1;                            break;            }       }   }}

This snippet is part of a huge function. If you would replace it by:
if (keys[SDLK_SPACE]){    if (shoot)    {        ShootBullet();    }}// and obviously move the shooting code to the ShootBulletFunction

It would be much more readable already. If you apply this principle consistently thoughout your code, eventually your main function should look something like this:
int main(int argc, char **argv){    InitSDL();    InitOpenGL();    InitGameData();    RunGameLoop();    ShutdownSDL();    return 0;}

Which is much more readable IMO.
You can help yourself into doing this by forcing yourself not to use functions with more than, say, 10 lines of code (this rule is not flexible enough for most cases, but you should break it as little as possible).

- Use meaningful names. I do not consider 'barray' a meaningful name. Assuming it is a an array with bullets 'bullet_array' would be more descriptive. 'drawobj()' is also not very good. I have no idea what it's supposed to draw. If it daws the player you could call it DrawPlayer(), for example.

- Use constants variables instead of hard-coded numbers (you already did this for some variables, like SCREEN_WIDTH and SCREEN_HEIGHT). You frequently use constant numbers in your code:
    glVertex2f(-5+player.pos[0],-10+player.pos[1]);    glVertex2f(-5+player.pos[2],-10+player.pos[3]);    glVertex2f(-5+player.pos[4],-10+player.pos[5]);

I have no idea what the -5 and -10 constants are supposed to be. If I assume here that they are some sort of borders, I could replace it by:
    glVertex2f(PLAYER_LEFT_BORDER_OFFSET  + player.pos[0],               PLAYER_RIGHT_BORDER_OFFSET + player.pos[1]);    glVertex2f(PLAYER_LEFT_BORDER_OFFSET  + player.pos[2],               PLAYER_RIGHT_BORDER_OFFSET + player.pos[3]);    glVertex2f(PLAYER_LEFT_BORDER_OFFSET  + player.pos[4],               PLAYER_RIGHT_BORDER_OFFSET + player.pos[5]);// and of course you should define the constants somewhere in the top of your file:const int PLAYER_LEFT_BORDER_OFFSET  =  -5; const int PLAYER_RIGHT_BORDER_OFFSET = -10; 

Note that this also has the advantage that if the left border changes, you need to change only in one location (instead of many; the -5 turns up alot in your code).

- And finally, what FReY said: you could go for a bit more abstraction. This is the hardest part, and can probably only be introduced by starting from scratch with a new design (on paper; one that shows every object in the game and how they relate).

Tom
An easy way to keep code well structured and designed is to jot it down in Pseudo code (Structured English). It’s a lot clearer than many actual languages and allows you to get your head around the code before you go ahead and actually implement it.
Jeff Plummer's thesis:
http://www.jeffplummer.com/Writings/Writings.htm


Kyle Wilson's website:
http://www.gamearchitect.net/


Gamasutra.com article:
http://www.gamasutra.com/features/20050414/rouwe_01.shtml



// ville
As far as specific design patterns: MVC. Model-View-Controller. I use this pattern on every game I write. Usually I end up mashing the Model and Controller into one class though.

The way it works is: "model" code takes care of the game logic. "view" code takes care of drawing.

Here's the rules you have to follow:
The model knows as little about the view as possible. In the best case, the model doesn't have a link to the view at all.
The view can know pretty much everything about the model.
The model contains all the important data.
The view can contain data, but only data relevant to drawing. None of the view's data is persisted. All of the view's data can be generated from scratch using only a model.

Also, you don't have to restrict yourself to one model class and one view class. Typically there will be several model classes and several view classes. Here's the important thing: every class must either be a model class or a view class. Really. There have been times when I've tried to have a single class work as both a model & view class simultaneously, and it always ends in disaster. It may be more work in the short-term to keep the model & view seperate, but trust me, it will make you happier in the long term.
I use MVC for some simple java games i write when im bored. the model would contain the data and the game logic. the viewport would actually be an interface, so i could implement it any way i want.

this is important, because you can create, say, a console view of your game, and a swing/awt version of your view, all you need to do is make different implementations. same thing with the controller, you could abstract it out, get input from keyboard, joystick, network. abstraction is the best part of game design.
---------Coming soon! Microcosm II.
Quote:Original post by ScottC
I apologize for the lack of info, I am using C++ with SDL and OpenGL, and i've made a real mess of my asteroids code.
http://rafb.net/paste/results/6O2hU981.html

Thanks for the articles, and information, I won't be buying any books though.

Edit: I wanted to know about like what to store in functions and stuff like that...


It doesn't look so messy to me... and it looks like C to me...

but I mean why do you really need much abstraction for a 100 line program? Isn't that kind of overkill? You can do it but I mean.. 100 lines of code isn't very hard to manage.
"It's such a useful tool for living in the city!"
Quote:Original post by Name_Unknown
It doesn't look so messy to me... and it looks like C to me...


The language should be somewhat irrelevant, many of the concepts in a C program can be applied to C++.

Quote:but I mean why do you really need much abstraction for a 100 line program? Isn't that kind of overkill? You can do it but I mean.. 100 lines of code isn't very hard to manage.


Abstracting in a 100 line app is a bit overkill, but it will make later code reuse easier. For example, if you abstract the code to create a window it's easier to copy and paste the abstracted code into a later project without having to worry about breaking anything.

It's also good practice for when you start writing larger programs. When it comes time to write a 10,000 line program you'll have some experience abstracting things (and probably have a better idea of some pitfalls you can avoid).
Quote:Original post by Name_UnknownIt doesn't look so messy to me... and it looks like C to me...


How can you tell a differance?

Quote:Original post by Will F
Quote:Original post by Name_Unknown
It doesn't look so messy to me... and it looks like C to me...


The language should be somewhat irrelevant, many of the concepts in a C program can be applied to C++.

Quote:but I mean why do you really need much abstraction for a 100 line program? Isn't that kind of overkill? You can do it but I mean.. 100 lines of code isn't very hard to manage.


Abstracting in a 100 line app is a bit overkill, but it will make later code reuse easier. For example, if you abstract the code to create a window it's easier to copy and paste the abstracted code into a later project without having to worry about breaking anything.

It's also good practice for when you start writing larger programs. When it comes time to write a 10,000 line program you'll have some experience abstracting things (and probably have a better idea of some pitfalls you can avoid).


That was the idea, being able to reuse the code, and to practice for writing larger programs.
I found its best to structure you code according to a timeline of events, and sort things according to when they should happen. For instance, lets pretend its a fixed frame system.
void MainLoop(){  while (!game.terminate)  {    ReadKeyControls();    RunGameLogic();    RenderGameGraphics();  }}

Then, break up the 3 timeframes into "states", so that both would probably use the same switch structure.
void RunGameLogic(){  switch( game.state )  {    case GAME_STATE_TITLE:    {      if (keypressed(ENTER)) game.state = GAME_STATE_PLAY;    }    break;    case GAME_STATE_PLAY:    {      if (keypressed(UP))      {        if (game.ship.speed < 100)          game.ship.speed += 1;      }      else if (keypressed(DOWN))      {        if (game.ship.speed > 0)          game.ship.speed -= 1;      }    }    break;    default: break;  }}


The exact structure here does have the flaw that it'll render PLAY 1 frame before it should, but thats gotten around by giving video it's own state variable that synchronizes at the end of the game loop.

This will help some for simpler games, what I used for bACMAN. As for larger games, the ideas carry, but the exact structure it way different.
william bubel

This topic is closed to new replies.

Advertisement