|
As graphics
gets pushed more and more onto specialized hardware, programmers are finally
getting the spare CPU cycles they need to bring game physics to realistic
levels. Unfortunately, as realism increases, so does the complexity of
the code. Starting off with the right data structures can greatly simplify
the tedious, error-prone task of programming and maintaining a physics
engine, and this article offers suggestions for helping to structure your
C++ code more efficiently .
Why Use
C++ instead of C?
It seems
like I spend about 10% of my time writing code and 90% of my time debugging
it, so clean code makes my job a lot easier. The C++ programming language
offers many nice extensions to C while keeping its clean, flexible syntax.
With it I can write clean, optimized code quickly so I can get to the
serious business of finding out why it doesn’t work. Here are the main
reasons why I prefer C++ over C.
1. Function
inlining. It is a common misconception that C++ produces slow, bulky
code and is therefore unsuitable for game programming. With function inlining,
C++ can produce functions that are as fast as macros. But unlike macros,
inline functions have strict type checking and are viewable in a debugger.
And let’s face it: if you really need blistering speed, you write it in
assembly. For a more detailed comparison of the performance of C and C++,
see [5] in the bibliography
at the end of this article.
2. Operator
overloading. If my house was burning down and I could take only one
feature of C++ with me, it would have to be the ability to overload operators.
Operator overloading allows you to use the language’s built in operators
(+, -, /, etc.) with user defined types as arguments. As an example, let’s
look at linear interpolating between two vectors:
const VECTOR
c = (1-u)*a + u*b;
The above
C++ statement reads as if it was copied directly from a textbook. The
fastest way to do the same operation in C is with macros:
VECTOR s,
t, c;
vmul(
s, a, 1-u );
vmul( t,
b, u );
vadd( c,
s, t );
What took
one line to write in C++, took four lines to write in C, and it’s is not
very easy to read. It can get worse. I didn’t fully appreciate C++ until
I wrote the physics engine for a racing game in C. The code took ten times
as long to write, and when I came back a week later to fix a bug, I could
barely follow what I had written.
3. Inheritance.
In C, building complex data types can be done by including structures
within structures. This makes accessing deep down members a real pain:
VECTOR R1
= body.PreviousState.Frame.Basis[1];
In C++,
data types can be built with inheritance, so any member variable or function
a base class had the derived class has as well. By using inheritance,
you can make the above C statement look like:
VECTOR R1
= body.Basis[1];
Now that
I’ve rambled on about how great C++ is, let me start describing some useful
data types.
The SCALAR
type
In any meaningful
physics program, you’ll need to represent decimal numbers. You could explicitly
make everything a float or a double, but what would you do if your program
requirements change mid-project and you suddenly need double’s instead
of float’s, or vice-versa? You’d have to globally replace every declaration
in your program. Or what if you’re randomly experiencing floating-point
overflows and you need some range checking in debug mode? Then you might
have to go through and wrap every arithmetic operation with a macro. In
any case, it’s probably not the best idea to hardcode a standard type
for your scalar quantities. The SCALAR type (see Listing
1) is there to abstract your scalar quantities so you can easily change
its internal representation.
|