A Basic Collision Detection


One of the basic things that virtually all games have is a collision detection method. In this case, all you need to determine is whether a particular moveable object is colliding with the level. (See Listing 14.12.)

Listing 14.12. Collision Detection Algorithm
 public bool HitTest(IMoveableObject obj, out Plane hitPlane) {     // Default to an empty plane     hitPlane = Plane.Empty;     // This object hasn't left the level, has it hit a wall?     IntersectInformation closestHit = new IntersectInformation();     if (levelMesh.Intersect(obj.Position, obj.Direction, out closestHit))     {         // This will always return true since you will always be hitting the         // outside of the level. Now you need to check to see if you're         // close enough to really be hitting the closest point         hitPlane = facePositions[closestHit.FaceIndex].GetFacePlane();         return (closestHit.Dist < obj.Radius);     }     return false; } 

This method should go into the level class, in case you didn't gather that already. It returns a Boolean value to determine whether you've hit and also a plane (as an out parameter) that will be the object that you've actually hit. For the player, this plane is irrelevant, but the bullets that are fired require it. First, the code calls the Intersect method on the mesh, which tells you based on an object's position and direction whether or not they will collide. Because the tank will always be inside the level that is walled in, this method will always return true. After it returns TRue, you check the distance between the object and the obstacle (which is returned in the IntersectInformation structure) and return true only if the distance is less than the radius of the object you're checking.

What about setting the plane variable? It calls a method on an object you've never created. Declare the variable in the class now:

 private SingleFace[] facePositions = null; 

I'm sure you've just realized that you haven't declared the SingleFace object yet either. See Listing 14.13 for the implementation of this object.

Listing 14.13. The Single Face Object
 private struct SingleFace {     public Vector3[] positions;     public Vector3 singleVertex;     public Vector3 singleNormal;     /// <summary>     /// Return the plane that this face creates     /// </summary>     /// <returns></returns>     public Plane GetFacePlane()     {         return Plane.FromPoints(positions[0], positions[1], positions[2]);     }     public Plane GetFacePlaneNormal()     {         return Plane.FromPointNormal(singleVertex, singleNormal);     } } 

There are two ways to create a plane. One is to use three points (which happen to make a triangle, which is the primitive that Direct3D uses to render its data), and another is to use a single point and its normal. Because the normal is perpendicular from the plane, it's relatively easy to calculate the plane from those two points as well. You'll notice that the single face class will store both and return the plane by using either the points or the normal. How do you create the array of these faces? Add the code in Listing 14.14 to your constructor for the level (at the end of the method, naturally).

Listing 14.14. Creating the Face Objects Array
 // Allocate the correct number of faces facePositions = new SingleFace[levelMesh.NumberFaces]; using (IndexBuffer ib = levelMesh.IndexBuffer) { // Find each face, first by locking the data short[] faces = ib.Lock(0, typeof(short), LockFlags.None,     levelMesh.NumberFaces * 3) as short[]; using (VertexBuffer vb = levelMesh.VertexBuffer) {     // Get a list of triangles that make the walls and floors     CustomVertex.PositionNormalTextured[] verts = vb.Lock(         0, typeof(CustomVertex.PositionNormalTextured),         LockFlags.None, levelMesh.NumberVertices) as         CustomVertex.PositionNormalTextured[];     // Now, find each face vertex position     int faceIndex = -1;     for(int i = 0; i < faces.Length; i++)     {         if ( (i % 3) == 0)         {             // Allocate the position array             facePositions[++faceIndex].positions = new Vector3[3];         }         facePositions[faceIndex].positions[i % 3] = verts[faces[i]].Position;         facePositions[faceIndex].singleVertex = verts[faces[i]].Position;         facePositions[faceIndex].singleNormal = verts[faces[i]].Normal;         }         // Make sure to unlock the buffer         vb.Unlock();     }     // Make sure you unlock the index buffer     ib.Unlock(); } 

What you do is actually walk all the data in the mesh and store every triangle that will be rendered. The levels aren't very big, and this step will give you exact planes that are hit, which makes calculations easier later. So first, you allocate the array of faces using the number of faces in the mesh as a count because that's what you'll be storing. Next you want to look through the index buffer of the mesh by locking it and getting the list of indices back. Once you have the list of indices, you can lock the vertex buffer as well because as you walk through the list of indices, you need to find the associated vertex information from the vertex buffer. The level mesh vertex data includes position, normal, and texture information, so you use this type when locking the buffer and getting the array back.

With all the data loaded, you can scan through the list of faces. Each triangle consists of three indices, so for every three indices you've seen, you increase your face counter and create a new array of three "positions" in your single face array.

You then store the position of the vertex referenced by that index (and the normal) into your array. After you go through each of the indices, you can unlock both the index and vertex buffers because you no longer need them.

Construction Cue

An index buffer is used to store indices into a vertex buffer, which allows you to render the same vertex multiple times without needing to declare duplicate vertices. Vertex buffers are used to store vertices efficiently.

See the DirectX documentation for more information on index and vertex buffers.




Beginning 3D Game Programming
Beginning 3D Game Programming
ISBN: 0672326612
EAN: 2147483647
Year: 2003
Pages: 191
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net