I made my first JigLib Demo! Check it out.
If you don't know what JigLib is yet, you are really missing out. Its a great project I'm proud to be the on the team of. It is a 3D physics engine (currently only for Papervision3D, but has been ported to Sandy/Away). It is a port from the JigLib engine done in C. For more information on the project, check out the blog.
I don't really want to give a bottoms up rundown on how jiglib works, so I'm just going to point out a few things that will help you pull off effects like you see in this demo - both from the jiglib point of view, but also from a general pv3d and programming angle.
This environment is actually very simple. I have a bitmap for the floor, a lamp model, and a bitmap for the cubes. I dynamically tint the cube materials to give it a little more depth and variety. One thing you will notice is that each cube, and each side of each cube, gets its own material. If you are wondering why, I did this to allow for the bullet holes to be drawn directly onto the material. I use a movie material so that it is easy to just add a bitmap into with a specific blend mode, and then forget it.
The environment for JigLib is very similar. Each cube is simply a "skin" for a class that represents a cube in JigLib. This class is called "JBox". You can think of a JBox as simply the "form" of a cube - it has position and rotation, which are transfered to the object that it is skinning. This it the general way that JigLib works. There are unique JigLib objects which use DisplayObject3D's in Papervision as a skin. All transforms done to the JigLib physics object is then reflected on the DisplayObject3D. JigLib has physics objects for Planes, Cubes (Box) and Spheres. It also includes logic to generate a car with wheels, using a special wheel class and an extension of the JBox class.
So, each cube is controlled by a JBox - and the floor is a JPlane for them to bounce on. There were some hit detection problems I was having with the plane, so I also added a JCube underneath the plane to give extra "floor" for the objects to run into. This is a hack fix, but it seems to help. Something else you can play with to help collision is the timing used by the physics engine. A lower speed will mean that things will move slower, and detect more collisions more accurately.
The Gun Shot
The gun shot is made up of a couple different parts. The gun itself actually "shoots" where it is looking - which is always 2000 in front of the barrel. The only time this is changed is when a hit is detected on a cube. When the mouse clicks on a cube, the target is changed to the exact coordinates of the hit.
The actual hit is determined by the mouse click. Take a look at the following code:
var hitPoint : Number3D = new Number3D(event.renderHitData.x, event.renderHitData.y, event.renderHitData.z);
var force:Number3D = new Number3D(hitPoint.x-camera.x, hitPoint.y-camera.y, hitPoint.z-camera.z);
var rb:RigidBody = skins[event.displayObject3D];
rb.AddWorldForce(new JNumber3D(force.x, force.y, force.z), new JNumber3D(hitPoint.x, hitPoint.y, hitPoint.z));
hitPoint records where the mouse was clicked in world space. Remember, this is only called when a cube is clicked. We then get the difference between that point and the camera, to get our "force" vector. To make it a constant strength, we simply normalize it (make it a length of 1), then multiply it by the force we want. We get our RigidBody from the dictionary I store the references in. Then, we use the function "AddWorldForce" - which takes two JNumber3Ds - the force vector, and the world hit point. This function will add the force to the object from world space - which saves us having to convert things into local coordinates.
The Bullet Trail
The bullet trail is a seperate class called LineOut. I called it LineOut since it fades itself out every frame. Once its invisible, it removes itself from the scene. To get the start and end points of the Line between the gun, I pass in two objects - the target that is positioned at the hit point, and the the muzzle flash that is positioned over the gun barrel. Before we can use the muzzle flash position, however, we need to update its world coordinates:
startPoint.world.calculateMultiply((startPoint.parent as DisplayObject3D).world, startPoint.transform);
Once the world matrix is updated with the current transform, we can use the world matrix to define the start point of the line. I use a segmented line because it looks better - but feel free to play with how many vertices are actually used.
The Bullet Hole
Since we used a seperate bitmap for each side of the cubes, we can alter them individually. This has more memory overhead, but I think it more than makes up for it by having bullet holes. The bullet hole position is determined, again, by the renderHitData that is passed when a cube is clicked. The U and V properties of the renderHitData tell us the "x" and "y" coordinates of the click on the material. Once we have that, we can simply add a bullet hole bitmap to our movie, and position it correctly:
var mat:MovieMaterial = event.renderHitData.material as MovieMaterial;
var hole : Bitmap = Sprite(mat.movie).addChild(new bulletAsset()) as Bitmap;
hole.blendMode = "overlay";
hole.x = event.renderHitData.u-hole.width*0.5;
hole.y = event.renderHitData.v-hole.height*0.5;
We take half the width and height to make sure that the bullet hole is properly centered on the hit point. One other thing to keep in mind is to define the clipping rect for the movie material when you initially make it. If you don't, your texture will become skewed if bullet holes go off the edge of the material, changing the size of the texture.
Those are the main parts of the demo - hopefully some things are helpful. I was hoping to show some fun uses of JigLib - and hopefully spawn some cool ideas in the process.