如果您要自己动手解决方案,我会建议以下内容。
地形
最好让地形是一个网格,只有每个顶点的高度不同。结果是一堆四边形,每个四边形在 (x, y) 平面上具有相同的尺寸。顶点具有不同的 (z) 值来构成斜率。网格排列使您可以轻松地确定在执行碰撞检查时必须测试哪些三角形是否相交。
如果这不是一个选项(地形预建在建模包中),您可能无论如何都希望使用内存中的网格,并存储(部分)在每个单元格内的三角形列表。
检查碰撞
最简单的方法是考虑你的演员在空间中的点。然后,您将确定该点的地形高度,如下所示:
- 确定点所在的网格单元格
- 获取与单元格关联的三角形
- 获取包含该点的三角形(在 (x, y) 平面内)
- 获取点的三角形/平面的高度
在“纯网格”地形的情况下,步骤 3 仅涉及单点/平面检查以确定我们需要 2 个三角形中的哪一个。否则,您必须对每个三角形进行点中点检查(您可能可以重复使用点/平面检查或使用 BSP 进行进一步优化)。
第四步伪代码:
point = [ x, y, z ] // actor position
relativePt = point - triangle.vertices[0]
normal = triangle.plane.normal
distance = relativePt DOT normal // (this is a dot-product)
intersection = [
point.x,
point.y,
point.z + distance / normal.z ]
这会计算从演员位置向上/向下的光线与三角形平面的交点。这就是那个 (x, y) 位置的地形高度。然后您可以简单地检查演员的位置是否低于该高度,如果是,则将其 z 坐标设置为地形高度。
物体(房屋,树木,...)
为每个对象提供 1 个或多个凸面碰撞体积,它们一起大致对应于其实际形状(请参阅UDN 上的此页面以了解虚幻引擎如何处理对象的碰撞外壳)。
您将不得不使用一些空间细分技术来快速确定在移动演员时要检查所有世界对象中的哪些碰撞。如果大多数运动是二维的(例如,只有地形和一些房屋),您可以使用简单的网格或四叉树(类似于具有进一步细分的网格)。一个 3 维选项将是octree。
空间细分的点与组织为网格的地形相同:将放置对象与空间中的单元/体积相关联,以便您可以确定要检查碰撞的对象集,而不是检查与所有对象的碰撞.
检查碰撞
- 使用您使用的空间细分技术获取“潜在的碰撞对象”;fe 获取actor当前网格单元中的对象。
- 对于每个对象的每个凸碰撞体积:
- 使用分离轴定理,确定actor是否与碰撞体积相交。有关一些实现提示,请参阅我对另一篇文章的回答(该问题与 2D 案例有关,但代码在很大程度上适用;只需将“边缘”读作“平面”)。
- 如果发生碰撞,请使用“违规平面”之一的法线将actor移动到该平面旁边。
注意:在这种情况下,将 Actor 的碰撞体积建模为一个长方体或 3 面圆柱体左右。
此外,您可能需要考虑为每个对象构建一个 BSP 树,并为您的演员使用轴对齐的边界框。但这有点超出了这个答案的范围。如果您的对象将具有更复杂的碰撞体积,那将会更快。
最后的想法
好吧,这已经是一个很长的答案了,这些只是一些粗略的介绍。碰撞是一个相当广泛的话题,因为您可以根据需要采取许多不同的方法。
例如,我没有介绍“跟踪碰撞”,即在演员移动时检测碰撞。相反,上面关于对象的建议会检查演员是否在对象内。这可能适合也可能不适合您的需求。
我也刚刚意识到我还没有涵盖演员与演员的碰撞。也许最好在 (x, y) 平面上碰撞 2 个圆,并额外检查它们的垂直空间是否相交。
无论如何,我真的要结束这件事。希望这至少会为您指明正确的方向。