XNA 3.1 中的碰撞检测

发布于 2024-12-02 16:30:31 字数 3590 浏览 1 评论 0原文

我目前正在使用 XNA 3.1 制作 3D 汽车游戏。这是一款出租车游戏。所以我的主车在游戏过程中遇到了交通车辆。我在对交通车辆和主车辆之间的碰撞检测进行编码时遇到问题。我使用了边界框方法而不是边界球方法,因为边界球没有正确覆盖车辆。 下面是我用来实现碰撞的代码。问题是当车辆左转或右转时,边界框不会相应改变。

我在update方法中写了这段代码。

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; 


下面是CalculateBoundingBox 方法

 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= BitConverter.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);

}


如果有人可以帮助我解决这个问题,那将会非常有帮助。如果除了我使用的方法之外还有更好的方法来实现碰撞,请告诉我该方法。

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= BitConverter.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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南笙 2024-12-09 16:30:31

您在这里有几个选择。最简单的方法是根据车辆的世界变换来变换车辆的边界框(这里不需要投影或视图,因为在检查碰撞时您不关心相机位置。)

假设您已经有了车辆的原始边界框,

/// <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;
}

对于每辆车,使用该方法创建一个临时边界框以用于碰撞。仅测试相互之间转换后的边界框,并且不要覆盖原始边界框,因为每当车辆移动时,您都需要从源重新计算此框。

如果您使用的是多网格模型,请使用 BoundingBox.CreateMerged() 将它们组合起来以获得包含整个模型的框,或者对每个子网格边界框执行碰撞(尽管如果不使用某种加速结构,这可能会变得昂贵)。

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).

何处潇湘 2024-12-09 16:30:31

我一直使用的是一种非常简单的方法,几乎​​可以适合任何情况。就是这样:

//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;
    }

您可以将所有球体更改为盒子,但这可能会起作用。此外,我所做的是将位置一次移动一个轴(X 轴,然后 Y 轴,然后 Z 轴)。这会产生更平滑的碰撞。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文