简体   繁体   中英

Most efficient way to compare all collision boxes?

I'm trying to come up with a collision algorithm for my game but am struggling on the method of implementing it. I have a collision box object which contains all the relevant collision data, then a vector of CollisionBox* in my game object to handle every collider.

However my method requires calling the same function 4 times for each collision, and the nested loops guarantee that the same collisions will be checked multiple times before the loop is done, and this is called every frame so will be very poor on performance. Here is what I have wrote

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

There are many ways to improve this code for performance.

First, the best would be to put your collision data together, in a contiguous manner. Your vector should contain the minimum required to test the collision. You can use SOA instead of AOS if that helps.

Then your collision algorithm is incorrect. You are not checking if the shape overlap, but it the shape has a vertex inside the other. This don't cover such collisions:

        o----o
   o----|    |---o
   |    |    |   |
   o----|    |---o
        o----o

As you can see, no vertices are inside the other polygon, but definitely collide.

Also, your data is incorrect in the sense that it contains much more data than needed. To represent an align box in memory, you only need two vectors:

Top left
   o--------|
   |        |
   |        |
   |--------o Bottom right

Then implementing the AABB collision (in 2D or 3D) becomes quite simple.

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

To upgrade the performance further, you'll need other methods such as space hash partitioning, Quadtrees/Octrees or other method.

If you want performance, always measure and identify the bottlenecks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM