Monday, September 3, 2007

Initialization order

This week I've integrated the Chipmunk 2D physics library into my own game and have done the initial setup for my vehicle, based on the moon buggy tutorial that is available with the Chipmunk library.

Several problems reared their heads in the course of this. One is that, because Chipmunk uses basic Euler integration, springs can be made to misbehave very easily. If you dial the stiffness of the shock absorbers up, there is a point beyond which they overshoot in the integration step, which leads to wild oscillations and the complete destruction of the simulation.

The other big problem had to do with initialization order. This is a major problem in professional game engines, too. Here's an example from my program:

const vec2 chassis_verts[] =
vec2(-5, 1),
vec2(-2, 2),
vec2(2, 2),
vec2(5, 1),
vec2(6, 0),
vec2(6, -1),
vec2(5, -2),
vec2(-5, -2),
vec2(-6, -1),
vec2(-6, 0),
const int num_chassis_verts = sizeof(chassis_verts) / sizeof(chassis_verts[0]);

const float chassis_mass = 5.0f;
const float chassis_moment = cpMomentForPoly(chassis_mass, num_chassis_verts, chassis_verts, vec2(0, 0));

class Rover

chassis = new cpBody(chassis_mass, chassis_moment);

cpBody * chassis;

Rover g_rover;

The code above does not, in general, work.

In C, you can lay out data structures using initializers; the data is resolved into a memory image at compile time, so nothing needs to be done at runtime.

C++ has classes, which have constructors. If you make a statically-defined object, C++ inserts its constructor into a list of constructors to be run at startup. If one startup constructor depends on the results of another startup constructor, you may or may not get what you want, depending on the order they are run. In general you can't control the order (though some compilers have #pragmas for helping establish rough ordering), and the compiler makes no attempt to analyze dependencies to put them in the right order.

The original Chipmunk sample application dynamically allocated all of its objects. I generally try to avoid explicit dynamic allocation when I can since then you have to explicitly deallocate objects. The one thing explicit allocation does give you, though, is explicit control over the order in which constructors are run.

All this has made me think about whether other languages would be better. Lots of other languages would not have this problem, but they won't do any compile-time cooking of data, either.

At the moment I am debugging a problem with the wheels when the torque is too high.

No comments: