Here we are, with nine articles behind us, and only one left to go. It's unfortunate that I won't have time to take this any further, since there a lot more things I could go over, but we've gotten off to a good start in Windows game programming, and there are any number of places you can go from here: input devices, sound effects and music, scripting, the DirectX Graphics API, etc. There are lots of articles covering things like this to be found at GameDev.Net, or there's always the DirectX documentation.
In any case, to close the series out, I'm going to show you a few little things you can use while developing your games. A lot of these, like organizing large programs logically into multiple source files, are going to be necessities when you start building up a full game. For most of today's article you won't actually need knowledge of DirectX to follow along, so don't worry if you've missed previous articles in the series. All set? Let's start with the topic I just referred to: organizing programs.
All of the demo programs I've shown you along the way in this series have been relatively short. The source file for the most recent one, on adding characters to your game, was about a thousand lines long, but that includes comments and whitespace, and I use both quite a bit. Even so, when you start putting a full game together, you'll quickly find that putting all your code in a single source file just won't work. It's not very organized that way. Sure, you can use Visual C++ to search for functions pretty quickly, but it's still much better to have your program logically broken up so you can find things when you need them. Also, it's nice to be able to jump from one function to another just by switching documents, or to compare code from two documents side by side.
Organizing a program in C++ is easy: if each class has its own source and header files, you'll always be able to find what you're looking for. For C programs it's not so well-defined, so you should just do your best to group functions which serve similar purposes together. To give you an example, I'll show you what my source files for Terran look like. There are quite a few, but it makes it easy for me to know where everything is.
So hopefully that will give you an idea how to keep source files organized. I also have a large header file called stdafx.h, which contains declarations for a bunch of structure types, function prototypes, extern statements for global variables, and about five hundred million #define statements. If you haven't seen it before, the extern keyword allows other source files to access a global variable that's been declared in a different source file. It's just a qualifier that goes on the front of a variable declaration, like this:
extern int bImageLock; extern STATE sGameState;
By including these extern statements in a header file, you can just include the header file at the top of every source file, and you'll have access to all your globals. The other thing to make sure you do with header files is to avoid including things like type declarations multiple times. For this, you use the #if and #endif directives. The way it's usually done is to check if a certain constant has been defined. If not, define it, then include all the stuff you need. That way, the next time that block of code is encountered, the constant has already been defined, so your declarations are only included once. For example:
#if !defined(_GAME_HEADER_001_INCLUDED) #define _GAME_HEADER_001_INCLUDED // ... constant declarations and such go here... #endif
There are a lot of blocks like this inside the main Windows headers, which is why using #define WIN32_LEAN_AND_MEAN can keep a lot of unnecessary code out of your project builds. Most things you'll put in header files should only be included once, and so should be inside a #if block. But including external variables with extern should be included in every source file, so be sure to keep those statements outside of your #if block.
One last thing on this: if you're using Visual C++, you can also use a single line of code that reads #pragma once to accomplish the same thing. This line specifies that the header in which it is located should only be included one time in a build. Most #pragma directives are compiler-specific, though, so you'll need to use #if..#endif if you're not using Visual C++, or if you may work with your code on a different compiler one day.