开发者

Collision detection in XNA 3.1

I'm currently making a 3D car game using XNA 3.1. It is a taxi game. So my main vehicle encounters traffic vehicles during the game. I'm having problems with coding the collision detection among traffic vehicles and the main vehicle. I used the bounding box method instead of bounding sphere method because bounding spheres don't cover the vehicles properly. Below is the code i used to achieve collision. Problem with it is when the vehicle turns left or right bounding box doesn't change according to that.

I wrote this code in the update method.

carWorld = Matrix.CreateScale(1f) * Matrix.CreateTranslation(vehicalClassObs[0].Position);

 trafficWorld = Matrix.CreateScale(1f) * Matrix.CreateTranslation(carObject.Position);

        BoundingBox b=CalculateBoundingBox(carO);
        BoundingBox c=CalculateBoundingBox(car);


        Vector3[] obb = new Vector3[8];
        b.GetCorners(obb);

        Vector3.Transform(obb, ref carWorld, obb);
        BoundingBox worldAABB = BoundingBox.CreateFromPoints(obb);

                Vector3[] occ=new Vector3[8];
                c.GetCorners(occ);

                Vector3.Transform(occ, ref trafficWorld, occ);
                BoundingBox worldAACC = BoundingBox.CreateFromPoints(occ);



                if (worldAABB.Intersects(worldAACC))
                    col = true;
                else col = false; 

Below is the CalculateBoundingBox method

 public BoundingBox CalculateBoundingBox(Model m_model)
{

// Create variables to hold min and max xyz values for the model. Initialise them to extremes
Vector3 modelMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
Vector3 modelMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);

foreach (ModelMesh mesh in m_model.Meshes)
{

    Matrix[] m_transforms = new Matrix[m_model.Bones.Count];
    m_model.CopyAbsoluteBoneTransformsTo(m_transforms);
  //Create variables to hold min and max xyz values for the mesh. Initialise them to extremes
   Vector3 meshMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
   Vector3 meshMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);

  // There may be multiple parts in a mesh (different materials etc.) so loop through each
  foreach (ModelMeshPart part in mesh.MeshParts)
   {
     // The stride is how big, in bytes, one vertex is in the vertex buffer
     // We have to use this as we do not know the make up of the vertex
     int stride = part.VertexDeclaration.GetVertexStrideSize(0);

     byte[] vertexData = new byte[stride * part.NumVertices];
     mesh.VertexBuffer.GetData(part.BaseVertex * stride, vertexData, 0, part.NumVertices, 1); // fixed 13/4/11

     // Find minimum and maximum xyz values for this mesh part
     // We know the position will always be the first 3 float values of the vertex data
     Vector3 vertPosition=new Vector3();
     for (int ndx = 0; ndx < vertexData.Length; ndx += stride)
      {
         vertPosition.X= BitConverter.ToSingle(vertexData, ndx);
         vertPosition.Y = BitConverter.ToSingle(vertexData, ndx + sizeof(float));
         vertPosition.Z= BitC开发者_开发知识库onverter.ToSingle(vertexData, ndx + sizeof(float)*2);

         // update our running values from this vertex
         meshMin = Vector3.Min(meshMin, vertPosition);
         meshMax = Vector3.Max(meshMax, vertPosition);
     }
   }

   // transform by mesh bone transforms
   meshMin = Vector3.Transform(meshMin, m_transforms[mesh.ParentBone.Index]);
   meshMax = Vector3.Transform(meshMax, m_transforms[mesh.ParentBone.Index]);

   // Expand model extents by the ones from this mesh
   modelMin = Vector3.Min(modelMin, meshMin);
   modelMax = Vector3.Max(modelMax, meshMax);
}


// Create and return the model bounding box
return new BoundingBox(modelMin, modelMax);

}

If someone can help me to solve this problem it wil be very helpful. If there is a better way to achieve collision other than the way i used please let me know about that method.


You have a couple of options here. The easiest is to transform the vehicle's bounding box according to the vehicle's world transforms (no projection or view required here since you're not concerned about camera position when checking for collisions.)

Assuming you already have the vehicle's original bounding box,

/// <summary>
/// Transforms a bounding box for collision detection
/// </summary>
/// <param name="vehicleBounds">Original, object-centered bounding box that contains a car model</param>
/// <param name="vehicleWorldMatrix">Vehicle's world transformation matrix (does not include projection or view)</param>
/// <returns>An axis-aligned bounding box (AABB) that will com </returns>
protected BoundingBox TransformBoundingBox(BoundingBox vehicleBounds, Matrix vehicleWorldMatrix)
{
    var vertices = vehicleBounds.GetCorners();

    /// get a couple of vertices to hold the outer bounds of the transformed bounding box.
    var minVertex = new Vector3(float.MaxValue);
    var maxVertex = new Vector3(float.MinValue);

    for(int i=0;i<vertices.Length;i++)
    {
        var transformedVertex = Vector3.Transform(vertices[i],vehicleWorldMatrix);

        /// update min and max with the component-wise minimum of each transformed vertex
        /// to find the outer limits fo teh transformed bounding box
        minVertex = Vector3.Min(minVertex, transformedVertex);
        maxVertex = Vector3.Max(maxVertex, transformedVertex);
    }

    var result = new BoundingBox(minVertex, maxVertex);

    return result;
}

For each vehicle, use that method to create a temporary bounding box to use for collisions. Only test transformed bounding boxes against each other, and do not overwrite you're original bounding box as you'll need to recalculate this box from your source any time the vehicle moves.

If you're using a multi-mesh model, use BoundingBox.CreateMerged() to combine them to get a box that contains the entire model, or perform your collisions for each sub-mesh bounding box (though this can get expensive without using some sort of acceleration structure).


What I have been using is a very simple method which can fit almost any situation. Here it is:

//Create one of the matricies
//Vector3 loc = new Vector3(0, 0, 0); //Wherever the model is.
//Matrix world1 = Matrix.CreateTransform(loc);
private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
    {
        for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++)
        {
            BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere;
            sphere1 = sphere1.Transform(world1);

            for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++)
            {
                BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere;
                sphere2 = sphere2.Transform(world2);

                if (sphere1.Intersects(sphere2))
                    return true;
            }
        }
        return false;
    }

You can change all the spheres to boxes, but this might work. Additionally, what I do is move the location one axis at a time (X axis then Y axis then Z axis). This creates smoother collision.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜