Brad Wardell's views about technology, politics, religion, world affairs, and all sorts of politically incorrect topics.
Game development vs. Application development
Published on July 15, 2005 By Draginol In GalCiv Journals

The team is getting features in like a well oiled machine.  The new research screen just totally rocks. Kudos to Mudflap and Mormegil for getting that stuff humming.  BoogieBack and the Elf Girl (doncha just love these handles) made good progress for getting the new star base system in and the new freighters in.

Our newest team member, Jesse (no cool handle yet), has started on the ship battles.  We want the ship battles to be really impressive and we want ships to show damage.  Ever see Star Trek II/III where the Enterprise has phaser burns and such? We want that kind of stuff.

The big debate this week is something that's kind of an on-going thing.  I've been writing games now for 12 years. That's games on store shelves.  I'm not a great programmer as I've mentioned many times before.  But my coding style does lend itself to easy debugging and easy readability.  I.e. I can go back and look at my code from 4 months ago and know what I was doing and in a pinch, put it through the debugger with all the important stuff just a click or two away in a debugger watch. 

But I wouldn't program an application the same way as I program a game.  Most of our business is creating applications.  And when it comes to applications, robust coding techniques take the lead.  A well designed application still needs readable code, but the odds of going in and tossing out features or algorithms in a typical application on a regular basis are not as high as they are in gaming.

In a strategy game, debugging becomes critical because debugging isn't about finding bugs.  Debugging is about fine-tuning game-play.  The last couple months of development usually mean, for me, spending 90% of that time in the debugger tweaking playability.  And that means having structures and objects and classes that lend themselves to being easy to view in the debugger.  To me, CString is the devil.  STL is a pain.  I don't like iterators. Which means I really don't like container classes.  I understand the need for those things. I just find them a pain to deal with when I'm debugging.

The last few months of Galactic Civilizations II will mostly be about tweaking the AI.  Why did the AI build this kind of ship? What did the AI put together a fleet with those kinds of ships in them? Why did the AI not build a particular structure on that particular planet? Where in the heck is that AI ship giong? Why are players running out of money? Why does the morale on a planet fall so low after a certain point is reached? Why did the AI not build a certain type of star base in a certain sector? Why did the computer player declare war on the human player when he did? Why didn't the AI recognize the threat posted by the human player? Why did the AI offer help to that player despite being morally opposite of him?  Why did the AI choose to build that ship on that particular planet? How did the AI see my starship when it was over here in the corner? Why did the AI put their spending ratios and spend rate at that level? Why did the AI send their freighter there?  How much money per turn is a particular trade route established between AI player 1 and AI player 2 costing?  How many shield modules does that particular AI ship have on it? How much time is it taking the AI to research a typical technology when on Average intelligence? How much difference is there between different AI intelligence levels?

The questions go on and on.  And those questions create many subsequent questions.  The answer isn't to put a bunch of debug print statements in the code, that would take forever.  The answer, as a practical matter, is to try to make it such that you can always look at a particular ship, computer player, planet, colony, improvement, whatever and with a few clicks be able to see the numerical value of it.  And moreover, to be able to code it in such a way that it doesn't take long.

That means things like Arrays and pointers. Not special array types, but good old fashioned pClassStarShip pShipsInFleet[MAX_NUM_SHIPS_IN_FLEET]; type stuff.  This is the kind of thing that drives seasoned developers crazy because it's so prone to causing bugs later on.  One slip-up in a for loop or something and suddenly you're getting unexplained crashes that can take weeks to debug. 

The way I've tended to deal with that is to break down my stuff into lots of small functions.  So things that could potentially introduce some overrun don't happen.  I also don't allocate memory on the fly.  In 12 years of game development, none of my code has ever used a Malloc.  And I've only recently (mainly because I'm had to adapt to other people's code) had to create instances of things on the fly and destroy them when I was done.  My code has traditionally only created new things at the start of a game and deleted them at the end of a game.  A single function for creating the stuff and another to wipe it out.  Everything else is created (and stays) so I'm not messing with memory leaks, memory overrruns, etc. 

And those people who have played our games know that they're traditionally quite solid.  I don't need a standard template library or a CString or other "stability via compiler" type stuff.   My way isn't better as any general rule.  But I believe it is better for game development on a game with limited scope (I wouldn't recommend this method for a development team of 20 people, it still requires pretty disciplined coding).

So that was our debate this week.  Things are going well though.  Beta 3 is going to rock.


Comments (Page 1)
2 Pages1 2 
on Jul 16, 2005
You'll be in for quite a culture shock if you ever port your programs to .NET.
on Jul 16, 2005
Yea, As a C coder, C# .NET has been a pleasure to use. the VS IDE is getting quite nice too.
on Jul 16, 2005
What games have you been making with .NET?
on Jul 16, 2005
Ive been doing smallish games, just to learn more about C#. Im new to the whole OO world, so Im falling victum to trying to do C# like I would a C program, which is wrong. But Managed DirectX has been nice. I think there a battle over the speen of .NET, but I haven't seed it with 100's of sprites moving around (using Direct3D). Of course, I am not trying to do Quake or some other intensive app.
on Jul 17, 2005
I'm not a great programmer as I've mentioned many times before. But my coding style does lend itself to easy debugging and easy readability. I.e. I can go back and look at my code from 4 months ago and know what I was doing and in a pinch, put it through the debugger with all the important stuff just a click or two away in a debugger watch.

If your code can be debugged and understood by someone else, then you're probably a good programmer. If you couldn't do what you're saying, then you'd be a poor developper.

Allocating everything at the start and deleting all at the end of the program (or the loading of a level in games with levels) is sound, and I've seen it advocated elsewhere. The only problem with memory leaks is applications where control of the life cycle of objects is hard to know.
Iterators are useful when you want to hide stuff from others. In a game, you may not need to use them, but if you realise you need better performances like changing a list to a (hash) set, then having used an abstraction through an iterator helps. But then the syntax of the STL and C++ templates in general makes it really ugly in my opinion (I prefer java iterators for instance).
As for using array[FIXED_SIZE], it's not really a problem. The only problem with arrays is when they are not of fixed size. And a good debugger can evaluate methods, so you should be able to call MyStructure->GetElement(index) inside the debugger, which is about as fast as getting MyStruct[i].
I wonder how you manage to handle big galaxy sizes though: If one can't play big galaxies because of low specs system, you don't have the same array sizes for a small galaxies as for a big one so everything is not coded at compile time. You initialize memory on reading the settings and then don't change them instead?

I code mostly applications (it's my job), mostly in infrastructure layers though I did some UI. And that's BIG applications (hundredS of coders). I also code a game as a hobby and I tend to code the same way as I code my app (except for testing which I do differently as I lack an automated test engine for a hobby). I don't know exactly what should be different between applications and games coding. How would you qualify the difference? Size? Layers of code? Time you keep debugging/supporting the app/game?
on Jul 18, 2005
LDiCesare , in a game you have to be able to quickly see and change any value when you're tweaking it for playability. In that sense a game isn't as well defined as a normal app, so you have different needs when you code.
on Jul 20, 2005
Changing values and tweaking is what resource/text files and scripts are for. I don't really see much difference here. And in the app I work on at my job, I spend lots of time changing a boolean here, a float there, when I debug, in order to simulate a problem or revert to a stage of the scenario I would otherwise have to replay everything.from scratch (including maybe loading a model that can take 1 hour to load).
on Jul 20, 2005
Changing the built in types from C are not the problem.  It's debugging the classes that are the problem.  If Brad need to step through the code where the AI designs its ships, an array of the current ship designs would be much easier to debug in Visual Studio.net 2003 than a container class from the STL.  Visual Studio.net 2005 is supposed to have a lot better debugging tools, particularly for the STL, but it won't be released until November and that's a little long to put off debugging.
on Jul 21, 2005
So that's essentially a debugger problem. A simple thing like dbx allows to evaluate methods so seeing and dumping state of objects in the debugger is easy. I have a certain dislike for MS debuggers. They have nice features (set next statement can be a boon) but are not consistent in allowing one to call methods from the debugger (it sometimes work) and crash far too often. But then, I use a very old version of MSDev at work...
on Jul 21, 2005
As a software architect I find technologies like STL and libraries like Boost (www.boost.org) indispensible. I also think it's a bad idea to eschew those technologies just because Microsoft's debugger hasn't caught up to them yet. They allow you to write maintainable, readable, memory-leak-free code more quickly than if you had to implement your own linked list or btree every time you needed one. Also, it sounds a little odd to use a debugger for something other than strictly debugging (i.e., AI or game balance tweaking). It seems like it'd be a better idea to build instrumented code that allows you to log and extract data from the proper points in the game. Certainly STL containers are a lot easier to introspect and do crazy operations on than tStarsip* or something.

For tasks similar to this, i.e., monitoring the internal goings-on of a system from a standpoint of tweaking, rather than squasing bugs, I usually end up writing my own tools, and "leveraging" (I hate that word) stuff like scripting languages that have powerful C++ bindings (read: Python and the Boost Python Libraries).
on Jul 21, 2005
if you had to implement your own linked list or btree every time you needed one.

I think Brad's saying he uses simple structures like arrays rather than linked lists (which are just another kind of list, arrays do as well except for removal) or btrees or maps. I wonder how he deos without Sets. Iff he's got a limited number of them, he can use a bit on the contained structure, but that doesn't look very practical.
I also develop traces utilities to debug the ai rather than the debugger, but then Brad has shown with Galciv that he managed to produce an excellent ai with these "simple" tools. Note that I usually loathe traces, and add them on purpose only when there's a complex engine that I must monitor, and once it's fixed I remove the traces so they remain readable.
on Jul 21, 2005
I love these little articles, its make me realize that I am not the only person who goes batty while coding. Now to prove my battiness has anyone manage to fix a bug while they were sleeping? I woke up with the answer once at 3am and ran to the computer, my girlfriend though I was crazy, she quickly moved out never to be seen again

(the moving out part was a joke, needed a punchline, thanks ill be here all week)
on Jul 24, 2005

Successful game development is like playing a strategy game.  If I have 6 months budgeted towards AI development and a certain coding method takes say merely 10% more time to debug, then I've effectively lost a couple crucial weeks.  And so far, STL and the like look more like 30% time eaters when it comes to debuggin and at that point, you're talking 2 months lost.

on Jul 24, 2005
That's why I make my home project in java. Far easier to debug than C++. And the time not spent debugging can be spent optimising, so there's little or no performance loss even with a slower language.
on Jul 26, 2005
I suppose that I can understand where you are coming from on issues of the STL. However, I do differ with you on your opinions. For instance, using vector instead of hard arrays has been show to offer very little in the way of performance costs. It has the added benefits of bounds checking when in debug mode so that you can't have issues of stack or heap corruption that you might have with a raw array. Also, if you are using .net 2003, I don't understand what kind of debugging problems you could be having with the STL. I use .net 2003 and it debugs the STL just fine.

I suppose that whatever works for you works for you. As long as your code is easy to read, more power to you, but I would also advise that you remember the bit about how we "stand on the shoulders of giants." Learning to use the STL and other such APIs is one of the essential features of the adaptable programmer.
2 Pages1 2