Обнаружение столкновений в XNA 3.1

В настоящее время я делаю трехмерную автомобильную игру, используя XNA 3.1. Это игра такси. Таким образом, мой основной автомобиль сталкивается с транспортными средствами во время игры. У меня проблемы с кодированием обнаружения столкновений между транспортными средствами и основным транспортным средством. Я использовал метод ограничивающей рамки вместо метода ограничивающей сферы, потому что ограничивающие сферы не покрывают транспортные средства должным образом. Ниже приведен код, который я использовал для достижения столкновения. Проблема в том, что когда транспортное средство поворачивает влево или вправо, ограничивающая рамка не меняется в зависимости от этого.

Я написал этот код в методе обновления.

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

}


Если кто-то может помочь мне решить эту проблему, это будет очень полезно. Если есть лучший способ добиться столкновения, отличный от того, который я использовал, сообщите мне об этом методе.


person user922896    schedule 01.09.2011    source источник
comment
Я бы предложил использовать подходящую физическую библиотеку, такую ​​как Box2D (у которой есть xna версия). Я бы также подумал об использовании последней версии Xna: 4.   -  person George Duckett    schedule 01.09.2011
comment
Я создаю 3D-игру. Могу ли я использовать эту библиотеку и для 3D-игр? Лучше, если я смогу выполнять обнаружение столкновений без использования библиотеки.   -  person user922896    schedule 01.09.2011
comment
Если все ваши дороги плоские, вы можете рассматривать их как 2D, если вам нужно полное 3D, см. этот вопрос: 3D-физический движок XNA   -  person George Duckett    schedule 01.09.2011
comment
@ Джордж, настоящий физический движок, вероятно, излишен для этого приложения на данный момент.   -  person 3Dave    schedule 01.09.2011


Ответы (2)


У вас есть несколько вариантов здесь. Проще всего преобразовать ограничивающую рамку транспортного средства в соответствии с преобразованиями мира транспортного средства (здесь не требуется проекция или вид, поскольку вы не беспокоитесь о положении камеры при проверке столкновений).

Предполагая, что у вас уже есть исходная ограничивающая рамка автомобиля,

/// <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(), чтобы объединить их, чтобы получить блок, содержащий всю модель, или выполните свои коллизии для каждого ограничивающего прямоугольника подсетки (хотя это может быть дорого без использования какой-либо структуры ускорения). ).

person 3Dave    schedule 01.09.2011
comment
Спасибо за вашу помощь. Ранее я разместил некоторые коды в моем методе обновления, и он содержит приведенные выше отредактированные образцы кода. Не могли бы вы проверить мой метод обновления, а затем сказать мне, неправильно ли я делаю столкновение или нет. - person user922896; 02.09.2011
comment
Я попробовал это, используя ваш пример кода. но все же у меня такая же проблема. Не могли бы вы мне помочь? - person user922896; 07.09.2011
comment
Не могли бы вы уточнить, что у вас все еще есть такая же проблема? - person 3Dave; 07.09.2011
comment
Когда мой автомобиль движется, ограничительная рамка также движется вместе с ним. Но когда транспортное средство меняет свое направление, ограничивающая рамка не изменится. - person user922896; 08.09.2011
comment
Значит, он отслеживает положение, но не вращение? - person 3Dave; 08.09.2011
comment
Да, похоже, это проблема. Не подскажете, как решить эту проблему. Если у вас есть время, посмотрите коды, которые я разместил ранее, и предложите метод. Спасибо за помощь. :) - person user922896; 09.09.2011

Я использовал очень простой метод, который подходит практически для любой ситуации. Вот:

//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). Это создает более плавное столкновение.

person SupremeSteak1    schedule 16.12.2013