Preventing Chaos in your game code

Started by
6 comments, last by Postie 11 years, 8 months ago
Hi Everyone, I've been coding a simple game in C++ with OpenGL. I'm pretty new to creating games and though I've had a lot of college experience in coding with C++ and Java and .Net I've never really developed anything professionally on this large a scale. The thing is I'm worried things will become more and more disorganized as I progress in making the game.

So far the game is a maze where you load the maze data from a text file and then you have to navigate to the goal. It will progress from there but I want to go over how I'm implementing it.

the Game Loop:

Level1= new Grid("data/Testlvl.txt",20,70);
max_fps=2; //TODO may need to incorporate a file load or mabye just play game from start to finish
int fcount=0; //frame counter
long long fps_sum=0LL; //sum of frame rate
long long start=milliseconds_now();
//intialise player speed
Level1->player->Velocity.x=40; //40 pixels per second
Level1->player->Velocity.y=40;
while(!done) //Game LOOOP!
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //is there a message?
{ //peek will not halt program while it looks for a message
if(msg.message==WM_QUIT) // have we received a quit message?
{
done=TRUE;
}
else{ //if not deal with the window messages
TranslateMessage(&msg); //Translate the Message
DispatchMessage(&msg); //Dispatch the Message
}
}
else{ // if there are no messages

// Draw the Scene. Watch for ESC Key and Quit Messages From DrawGLScene()
if((active && !DrawGLScene())|| keys[VK_ESCAPE])
{
done=TRUE; // ESC Signalled a Quit
}
else{ //not time to quit, update screen
//drew scene in the if statement
while(FPS(start,milliseconds_now())>max_fps)
{/*wait*/}
if(fcount < 60)
{
fps_sum=fps_sum+FPS(start,milliseconds_now());
++fcount;
}
else
{
fps=fps_sum/fcount;
fcount=0;
fps_sum=0LL;
}
start=milliseconds_now();
SwapBuffers(hDC); //SwapBuffers (double buffering)
}
}
} if (!gameover && active) // If Game Isn't Over And Programs Active Move Objects
{
if (keys[VK_RIGHT])
{
Level1->MovePlayer(M_RIGHT);
}
if (keys[VK_LEFT])
{
Level1->MovePlayer(M_LEFT);
}
if (keys[VK_DOWN])
{
Level1->MovePlayer(M_DOWN);
}
if (keys[VK_UP])
{
Level1->MovePlayer(M_UP);
}

Level1->Step(start);// what happens next?
}
//outside of live play:
if(keys['A'] && !ap)
{
ap=TRUE;
max_fps++;
}
if (!keys['A']) // If 'A' Key Has Been Released
{
ap=FALSE; // ap Becomes FALSE
}
if(keys['Z'] && !zp && max_fps>2)
{
zp=TRUE;
max_fps--;
}
if (!keys['Z']) // If 'A' Key Has Been Released
{
zp=FALSE; // ap Becomes FALSE
}

//*********update scene****************
/// Beat first Level Snippet
if(Level1->player->isTouching(*Level1->goal))
levelend=true;
///end of snippet
}



So right now inorder to switch scenes in the game loop I set global flags to true and false ( good or bed way to do it) and the DrawGLScene() will check the flags and determine which scene to draw,

After declaring a few setup variables I move everything along via time, I even force a max frame rate so that i can control the FPS. (I did this starting out just because I could and now I'm thinking about turning the FPS into something like a reward system collect items increase the FPS makes for smooth gameplay)

All my classes are contained within the Grid Class, the Grid Class will contain a player and a List of objects (coins enemies and such all will inherit the MObject class which has a bunch of virtual functions so I can iterate through the list and call Step() and Draw() functions. Step basically updates all the objects positions and other such statuses given that point in time. everything goes through Grid so when the user enters any key commands the Grid can determine what information flows to what objects it's managing. I keep most things public right now but I hope to eventually makes the objects private and get implement public functions to keep things from getting confuzzled.

so kind of breaking it down to the flow so far psuedo codeish:

GameLoop:
DrawScene:
[chooses what scene to draw based on flags]
assuming game is running
Draw header()
Grid->Draw()
Draws grid
Draws Players
Draws Goal
todo: draw enemies
todo: draw items
Isgamerunning?
Check for input
Move player, enemies
Step
grid.Step()
update animated items, players enemies,

Are game changingg conditions met
progress game



I'd really appreciate constructive criticism and how to make it better, methods to keep things organized, what your own ways to coding the loop are.

I hope my post makes some sense too
Advertisement
This from my phone so excuse the horrible grammer/spelling.

For now i wouldnt worry about the chaos (spaghetti code) sounds like you just need a little more experience. So just keep on coding. Thats how youll get that experience.

Imho the biggest killer of projects is the same mentality that youre getting into. That everything has to be perfect feom the get go. Take a great example... diablo 3. Blizzard sold billions in the first day and the game is still plagued with bugs two months after release.

Not saying its alright to make buggy games. But that productivity is very important. You should focus on finisging the game first and for most. Assuming you have some worth finishing. Then refactor once youre in the optomizing phase of your prohect.

So get back to coding. Play your game often while developing. And worry about fixing things when something is actually broken.
[ dev journal ]
[ current projects' videos ]
[ Zolo Project ]
I'm not mean, I just like to get to the point.
I usually refactor when I see one of the following:

1 - I have the same code in mutliple places - a good sign that the common functionality needs to be refactored out into its own method or object
2 - I have a largish glob of complex or hard to read code - a good sign that I should seperate the logic into multiple methods/classes.
3 - I keep having to tack on extra checks or variables to handle corner-cases, or the code is beginning to feel "hackish" - this is usually a sign that I need to rethink my design on a higher level.

I don't necessarily see any of this in your posted code, although these rules are somewhat subjective anyway. There may be idiomatic C++ concerns as well that I am not qualified to comment on.

As the complexity grows, you may find that you want to isolate your input handling code, or message dispatch, etc. Personally I try and avoid long if-else-else-else... chains if possible, they tend to confuse me when revisiting code later, YMMV.

An easy trap (for me, anyway) to fall into is to try overengineering too early - I may feel clever with the results at first, but later humbled when I find that I need my design to go a completely different direction anyway.
It is a good idea to think in systems. Don't update a single object, notify the system to update itself.

Your pseudocode example does this fairly well, much better than your actual code sample does.

Example: Rather than iterating over each particle in your main loop, have a particle system manager that runs every update; this in turn updates each of the active particle systems, which in turn iterate over every particle. Yes there is some overhead involved, but machines are multi-core multi-gigahz, and a few nanoseconds of overhead is a great tradeoff in exchange for keeping your sanity.
#frob This needs one of my favourite quotes: "Sanity? I don't remember having such a useless thing in a first place." ph34r.png

To the topic...

Anyway if you want to investigate some more into how to "prevent chaos in code" - try reading something on design patters, language conventions, naming conventions and it's never too late to start to use F.e. Doxygen style commenting, that is actually very helpful to keep code nice and clean...

Also I recommend reading something on coding style, naming conventions, etc. - and try to keep single coding style and naming convention in every single of your project (and don't always use just one, use different coding styles in different projects - you might once come to contribute to applications on SourceForge - then it's huge advantage to adapt to different coding styles) smile.png

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

While I agree that productivity is important, and that your coding will improve with time, I also feel that you yourself can increase the quality of your coding style greatly by adopting a few tricks and tips at a time and integrating them one by one into any new code you write. Basically: Don't beat yourself up over bad code, but don't pretend it'll get better on its own and actively invest in learning cleaner coding practices.

I'd strongly recommend Code Complete (2nd Edition) by Steve McConnell. Best programming book I've ever read - It contains tons of good "Do this to improve your code quality, and here's why" advice.

I also wrote a series of posts in a thread about half a year ago about some clean coding practices. There are multiple good posts if you keep reading down (particularly the second page), and should be a good place to pick and choose some techniques.
As others have said, reading books and other resources about clean code, coding style, and design patterns are all very useful.

Here's my advice:
- Use static analysis tools to check for styling issues and possible bugs. For Java, there's Checkstyle and Findbugs. For Python, you have pep8, pylint, and pyflakes. There are equivalents for other languages; just check google.
- Check your code/test coverage. (You are writing unit tests, right?) I found this immensely helpful in pursuing game programming as a hobby. Before I started doing rigorous testing and coverage analysis, I was just kind of thrashing around and things just sort of worked. Now, when I implement a new feature, I check my test coverage. If there's a large body of code with no coverage, I stop coding and I test it. If it can't be tested easily, it probably needs to be refactored.
- Write as much as you can in a pure functional style. That doesn't mean you have to go crazy with functional programming concepts, but the fact is purely functional code is much easier to test. So if you can move a bunch of the complexity into small, easily testable functions, you'll that you'll have greater confidence in your code and that it's easier to make changes. (BTW, John Carmack has talked about the benefits of writing functional-style code: http://www.altdevblogaday.com/2012/04/26/functional-programming-in-c/)

That's my 2 cents.
First things first. Does it work? If not, get it working. Then think about refactoring.

A good metric for determining if refactoring is required is if the code makes sense to you at a glance a few weeks or months later. You can often overlook obvious design flaws when the code is fresh in your mind.

IMHO, it's better to code an imperfect solution and then improve it later (if you have time) than spending hours agonising over producing the perfect design first time. I know this because I'm guilty of it all the time.
[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler

This topic is closed to new replies.

Advertisement