JavaScript EditorFree JavaScript Editor     Ajax Editor 



Main Page
  Previous Section Next Section

General Game Programming Guidelines

Next I want to talk about some general game programming techniques and philosophies that you should think about and try to adopt (if you can) to make game programming much easier.

To begin with, video games are ultra-high-performance computer programs. No longer can you use high-level APIs for time-critical or memory-critical code sections. For the most part, you must write everything yourself that is related to the inner loop of your game code, or else your game will suffer terrible speed and performance problems. Obviously, this doesn't mean that you can't trust APIs like DirectX, since DirectX was written to be as high-performance and "thin" as possible. But in general, avoid high-level function calls.

With that in mind, take a look at a list of tricks to keep in mind as you're programming.

TRICK

Don't be afraid to use global variables. Many video games don't use parameters for a lot of time-critical functions, instead using a global parameter passing area. For example, say a function looks like this:

void Plot(int x, int y, int color)
{
// plots a pixel on the screen
video_buffer[x + y*MEMORY_PITCH] = color;
} // end Plot

Here the body of the function takes less time than the function call. This is due to the parameter pushing and popping on the stack. In this case a better method might be to create a global parameter passing area and then make assignments before a call, like this:

int gx,gy,gz,gcolor; // define some globals

void Plot_G(void)
{
// plot a pixel using globals
video_buffer[gx + gy*MEMORY_PITCH] = gcolor;

} // end Plot_G

TRICK

Use inline functions. You can improve the preceding trick even more by using the inline directive to get rid of the function call completely. The inline directive instructs the compiler to make its best attempt to put the code for the function right where it's called, rather than making the actual function call. Of course, this makes bigger programs, but speed is more important. Here's an example:

inline void Plot_I(int x, int y, int color)
{
// plots a pixel on the screen
video_buffer[x + y*MEMORY_PITCH] = color;
} // end Plot_I

Notice that I didn't use globals because the compiler will in effect perform the same type of data aliasing. However, globals would come in handy if only one or two of the parameters were changing between calls because the old values could be used without reloading.


TRICK

Always use 32-bit variables rather than 8- or 16-bit. The Pentium and later processors are totally 32-bit. This means that they don't like 8- or 16-bit data words, and in fact, smaller data can slow them down due to caching and other related memory addressing anomalies. For example, you might create a structure that looks something like this:

struct CPOINT
{
short x,y;
unsigned char c;
} // end CPOINT

Although creating this structure may seem like a good idea, it's not! First, the structure itself is now 5 bytes long—(2*sizeof(short) + sizeof(char)) = 5. This is really bad, and it's going to wreak havoc on the memory addressing. A better approach is the following structure:

struct CPOINT
{
int x,y;
int c;
} // end CPOINT

C++

Tip STRUCTs in C++ are just like CLASSes, except that they have default PUBLIC visibility.


This new structure is much better. For one thing, all the elements are the same size—that is, sizeof(int) = 4 bytes. Therefore, a single pointer can be incremented on a DWORD boundary to access any member. Of course, the new structure is now (3*sizeof(int)) = 12 bytes, but at least it's a multiple of 4 or on a DWORD boundary. This is definitely going to improve performance.

In fact, if you really want to make things rock, you can pad all structures to make them multiples of 32 bytes. This is the optimal length due to standard on-chip cache line sizes in the Pentium class processors. You can pad manually by adding dummy variables, or you can use a compiler directive (the easy way). Of course, padding may waste a lot of memory, but it may be worth it for the increase in speed.

TRICK

Comment the heck out of your code. Game programmers are notorious for not commenting their code. Don't make the same mistake. Clean, well-commented code is always worth the extra typing.


TRICK

Program in a RISC-like (reduced instruction set computer) manner. In other words, make your code simple rather than complex. Pentium and Pentium class processors in particular like simple instructions rather than complex ones. And making your code longer, with simpler instructions, makes it easier for the compiler. For example, don't do this:

if ((x+=(2*buffer[index++]))>10)
{
// do work
} // end if

Instead, do this:

x+=(2*buffer[index]);
index++;

if (x > 10)
{
// do work
} // end if

There are two reasons for coding like this. First, this approach allows a debugger to insert break points between code sections. Secondly, coding this way makes it easier for the compiler to send simplified code to the Pentium, which allows it to process more code in parallel using multiple execution units. Complex code is bad!


TRICK

Use binary shifts for simple multiplication of integers by powers of 2. Since all data in a computer is stored in binary form, shifting the bit pattern to the left or right is equivalent to multiplication or division, respectively. For example:

int y_pos = 10;

// multiply y_pos by 64
y_pos = (y_pos << 6);  // 2^6 = 64

Similarly,

// to divide y_pos by 8
y_pos = (y_pos >> 3); // 1/2^3 = 1/8

You'll see more tricks like this when you get to the optimization chapters. Cool, huh?


TRICK

Write efficient algorithms. All the assembly language in the world isn't going to make an n^2 algorithm go faster. It's better to use clean, efficient algorithms rather than brute force.


TRICK

Don't optimize your code as you program. This is usually a waste of time. Before you start heavy optimization, wait until you're done with a major code block or until you're done with the whole game. Working this way will save you time in the end because you won't have to deal with cryptic code or optimizations that aren't necessary. When the game is done, that's the time you should start profiling and finding problem areas to optimize. On the other hand, don't program sloppily.


TRICK

Don't write a lot of complex data structures for simple objects. Just because linked lists are cool doesn't mean you should use them for a fixed array that you know will always be around 256 items. Just allocate it statically and be done with it. Video game programming is 90% data manipulation. Keep your data as simple and visible as possible so you can access it quickly, do what you need to, and move on. Make sure the data structure fits the problem.


TRICK

Use C++ sparingly. If you're a seasoned professional, go ahead and do as you please, but don't go class crazy or overload everything to death. In the end, simple, straightforward code is the best and easiest to debug. And I never want to see multiple inheritance!


TRICK

If you see that you're going down a rocky road, stop, back up, and take a detour. I have seen many game programmers start down a bad programming line and bury themselves. It's better to realize you made a mistake and redo 500 lines of code than to have a generally undesirable code structure. So, if you see a problem with what you're doing, re-evaluate it and make sure that the time you're saving is worthwhile.


TRICK

Back up your work regularly. When you're writing game code, you're going to lock up the system fairly frequently. Redoing a sorting algorithm is one thing, but redoing the AI for a character and the collision detection is another.


TRICK

Before you start on your game projects, be organized. Use reasonable filenames and directory names, come up with a consistent variable naming convention, and try to use separate directories for graphics and sound data rather than dumping everything in one directory.


      Previous Section Next Section
    



    JavaScript EditorAjax Editor     JavaScript Editor