问题描述
我正在尝试为我的游戏想出一个碰撞算法,但在实现它的方法上很挣扎。我有一个碰撞盒对象,它包含所有相关的碰撞数据,然后在我的游戏对象中有一个 CollisionBox*
向量来处理每个碰撞器。
但是我的方法需要为每次碰撞调用相同的函数 4 次,并且嵌套循环保证在循环完成之前将多次检查相同的碰撞,并且每帧都调用它,因此性能会很差.这是我写的
void Game::CheckCollisions() {
vector<CollisionBox*>::iterator it;
for (it = colBoxes.begin(); it != colBoxes.end(); ++it) {
//for each Box - compare the 4 corner points with every other Box,only compare different collision layers
Vector3 BoxPos = (*it)->mModel.GetPosition();
for (vector<CollisionBox*>::iterator it_2 = colBoxes.begin(); it_2 != colBoxes.end(); ++it_2) {
if ((*it) != (*it_2) && (*it)->colLayer != (*it_2)->colLayer && (*it)->isActive && (*it_2)->isActive) {
IsPointInside((*it)->tl,*(*it_2)); //tl
IsPointInside((*it)->tr,*(*it_2)); //tr
IsPointInside((*it)->bl,*(*it_2)); //bl
IsPointInside((*it)->br,*(*it_2)); //br
}
}
}
}
bool Game::IsPointInside(const DirectX::SimpleMath::Vector3& point,CollisionBox& Box) {
return (point.x >= Box.bl.x && point.x <= Box.tl.x) &&
(point.y >= Box.bl.y && point.y <= Box.tl.y);
}
解决方法
有很多方法可以改进此代码的性能。
首先,最好以连续的方式将碰撞数据放在一起。您的向量应包含测试碰撞所需的最小值。如果有帮助,您可以使用 SOA instead of AOS。
那么你的碰撞算法是不正确的。您不是在检查形状是否重叠,而是在形状内部有一个顶点。这不包括此类冲突:
o----o
o----| |---o
| | | |
o----| |---o
o----o
如您所见,另一个多边形内没有顶点,但肯定会发生碰撞。
此外,您的数据是不正确的,因为它包含的数据比需要的多得多。要在内存中表示一个对齐框,你只需要两个向量:
Top left
o--------|
| |
| |
|--------o Bottom right
然后实现 AABB 碰撞(在 2D 或 3D 中)变得非常简单。
auto aabb_intersect(CollisionBox const& a,CollisionBox const& b) noexcept -> bool {
return (
(a.tl.x <= b.br.x && a.br.x >= b.tl.x) &&
(a.tl.y <= b.br.y && a.br.y >= b.tl.y) &&
(a.tl.z <= b.br.z && a.br.z >= b.tl.z)
);
}
为了进一步提升性能,您需要其他方法,例如空间哈希分区、四叉树/八叉树或其他方法。
如果您想要性能,请始终衡量并确定瓶颈。