【问题标题】:Most efficient way to compare all collision boxes?比较所有碰撞盒的最有效方法?
【发布时间】:2021-01-27 17:29:53
【问题描述】:

我正在尝试为我的游戏提出一个碰撞算法,但我正在为实现它的方法而苦苦挣扎。我有一个碰撞盒对象,其中包含所有相关的碰撞数据,然后在我的游戏对象中有一个 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);           
}

【问题讨论】:

  • 检测您的代码以进行性能测量以找到瓶颈。鉴于详细而狭窄的背景,很难说出应该改变什么。
  • 例如,您可以尝试第一个it_2 框是当前it 框(或下一个),以避免执行冗余测试。
  • 如果碰撞盒不是全部堆叠在游戏世界的一小块区域中,您可能希望将地图划分为例如 200 * 200 个图块(总共 40,000 个图块)的网格。然后,您可以为每个网格图块维护与该网格接触的所有碰撞框的列表。这样,如果您想确定与某个碰撞盒的所有碰撞,您所要做的就是将该碰撞盒与该碰撞盒所接触的网格图块中的碰撞盒列表进行比较。您将不再需要与游戏世界中的所有碰撞盒进行比较。
  • 我之前评论中描述的方法只有在不是所有碰撞盒都堆叠在游戏世界的一小块区域时才有意义。如果是,那么您可能想改用R-tree

标签: c++ collision-detection game-physics


【解决方案1】:

有很多方法可以提高此代码的性能。

首先,最好将碰撞数据以连续的方式放在一起。您的向量应包含测试碰撞所需的最小值。如果有帮助,您可以使用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)
    );
}

要进一步提升性能,您需要其他方法,例如空间哈希分区、四叉树/八叉树或其他方法。

如果您想要性能,请始终衡量和识别瓶颈。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-22
    • 2019-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-10
    • 2011-10-29
    • 2020-10-24
    相关资源
    最近更新 更多