XNA 3.1 中的碰撞检测
我目前正在使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您在这里有几个选择。最简单的方法是根据车辆的世界变换来变换车辆的边界框(这里不需要投影或视图,因为在检查碰撞时您不关心相机位置。)
假设您已经有了车辆的原始边界框,
对于每辆车,使用该方法创建一个临时边界框以用于碰撞。仅测试相互之间转换后的边界框,并且不要覆盖原始边界框,因为每当车辆移动时,您都需要从源重新计算此框。
如果您使用的是多网格模型,请使用 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,
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).我一直使用的是一种非常简单的方法,几乎可以适合任何情况。就是这样:
您可以将所有球体更改为盒子,但这可能会起作用。此外,我所做的是将位置一次移动一个轴(X 轴,然后 Y 轴,然后 Z 轴)。这会产生更平滑的碰撞。
What I have been using is a very simple method which can fit almost any situation. Here it is:
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.