Wednesday, April 8, 2009

Ah, Physics!

The goal this time is to simply hook in the JigLibX physics engine, add some gravity and have the ship fall. Then put in a height map, probably the exact one from the JigLibX demo program and have the ship land on that.

Hooking in the JigLibX engine seems pretty simple, you initialize a new base physics object and set some configuration settings like gravity:

            physicSystem = new PhysicsSystem();
            physicSystem.CollisionSystem = new CollisionSystemSAP();
            physicSystem.EnableFreezing = true;
            physicSystem.SolverType = PhysicsSystem.Solver.Normal;
            physicSystem.CollisionSystem.UseSweepTests = true;
            physicSystem.NumCollisionIterations = 5;
            physicSystem.NumContactIterations = 15;
            physicSystem.NumPenetrationRelaxtionTimesteps = 20;
            physicSystem.Gravity = new Vector3(0f, -5f, 0f);

Every object you want to have a physical presence in the world then needs to have an instance of a CollisionSkin which defines how the object insteracts with others in the physical world, and if it moves (as apposed to being immobile like a heightmap) the CollisionSkin needs an instance of a Body object. Then you can add the object to the physics engine using a static method. To create a completely default object in the world you would do something like

Body body = new Body(); // just a dummy. The PhysicObject uses its position to get the draw pos
CollisionSkin  collision = new CollisionSkin(body);
PhysicsSystem.CurrentPhysicsSystem.CollisionSystem.AddCollisionSkin(collision);

The use of the static method worries me, I may want more than one physics system running at  a time for some effects and this could complicate that. For now it's works fine. I added the physics initialization code to the constructor of my PlayScreen, no need to do it at the Game level since not all screens will need physics, and created a PhysicalSceneItem object which creates the Body and CollisionSkin and automatically adds itself to the physics system. The PlayerShipSceneItem is now a child of that base class and uses the PlayerShipMeshShape to adjust the Collision item to match the shape and size of my ship (a simple rectangle for now) and sets some sensible Mass and Material properties such as surface friction, roughness and elasticity.

An important thing to remember is that on every Update call to the PlayScreen the physics engine needs to be updated and then the PhysicalSceneItem in it's Update call needs to adjust it Shapes translation and rotation to match that of it's physical Body instance. Otherwise nothing will ever visually happen. This can be tricky because the Shapes location information is stored in a matrix so if we had to adjust it we'd have to take it apart into translation, rotation and scale settings using Matrix.Decompose, make the adjustments and then put it back together. Luckily we don't have to do that now, though I'll have to do it later, because we don't care where the Shape was, we just want it to be where the Body says it is now. The body uses matrix's as well but keeps them separated into translation, scale and orientation, so we build the Shapes new matrix by multiplying them together into one:

                shape.World = Matrix.CreateTranslation(-center) *
                              Matrix.CreateScale(scale) *
                              body.Orientation *
                              Matrix.CreateTranslation(body.Position + center);

The 'center' Vector3D lets an object have a center point around which it rotates that is not the physical center of it's shape, I'm not using it right now and I'm not sure how it will behave with the physics engine... I might just pull it out.

So all put together, compiled and run and the ship obediently falls away from the camera! Yay! Now for the height map.

I pretty much bring the height map code directly from the JigLibX demo program. This setup uses a custom content pipeline to read in a 257x257 sized gray scale bitmap which it translates into a 3D Model and an array of heights which are stored in the Content directory. At run time the game loads the Model and the heights and creates a native JigLibX Heightmap instance. One potential problem I see immediately is that the model generated is over 4 megabytes in size, given how big I want levels to be and how many levels I want and that I want to come in under the total 50 megabytes size for the entire game, this is going to have to change. I'll have to store the bitmaps, the sample is 42KB stored as a .png, and create the Models at level load time. For now I'll leave that on the TODO list, I just want to see it in my game.

Hooking it up was once again rather simple, I made a HeightmapMeshShape and a HeightmapSceneItem derived from the PhysicalSceneItem, initialized them in the PlayScreen constructor, fired up the game... and thats when things went sideways.

Literally sideways. I was expecting to be looking down on the heightmap with the ship falling away from the camera and landing in the center of the map. But instead I got a nice, if unexpected, side view of the heightmap. Apparently 'which way is up' isn't the same for my fledgling game and the native JigLibX heightmap object. JigLibX itself is nutral as far as subjective directions go, as a good physics engine must be (there is no 'up' in space) but the heightmap object has a very definitive idea, 'up' is along the positive Y axis while I've been setting my game up to use positive Z as 'up'. Also, the JigLibX Heighmap ignores it's rotation matrix. Hrm, to change my game or the JigLibX Heightmap?

I spend a couple of hours trying to change the Heightmap. The pipeline wasn't too hard, I got the mesh rotated and showing properly and I think I got the colission part of the Heightmap playing along. I'm now looking down on it in the game and the ship falls into it and hits it. But the ships resulting movement based on the hit is all wonky. It goes careening off in odd directions and eventually falls through the world.

I give up. My game is in it's infancy and changing it will be much simpler than mucking about in the depths of the Heighmap physics object. It'll take me some time to get used to Y being up and X, Z being map coordinates, but I'll cope.

Once I've undone my changes, moved and re-oriented the camera and my ship falls and bounces off the ground. Yay!

One lingering thing, I went into 3DS Max and realigned my ship model to the new Y-is-Up thinking and re-exported it, replaced the one in my Content directory and re-built the project. But the ship was still oriented wrong. I had made some other changes to it, and those showed up so I know the new model was imported. I've tried several other things, and still the ship is oriented wrong. I suspect the Max fbx exporter is 'helping' me by re-orienting the model the way it thinks I want it, knowing that Y and Z axis flipping can be an issue. I'll have to figure out how to stop it from doing that.

Next: Player Input Wrangling

No comments:

Post a Comment