c ++实现平滑壁面滑动的平铺2D世界的碰撞检测和处理

时间:2013-12-03 20:44:19

标签: c++ collision-detection quadtree

我使用SFML 2.1进行图形处理,我的游戏结构非常接近SFML书籍(SceneGraph实现等) 我的世界主要包括角色(大约1-400,四处移动)和瓷砖(3600,静止),每次移动时我都会检查碰撞

在最糟糕的情况下,有大约400个字符移动和~3600个区块,我有4000个可能的碰撞实体和800个碰撞检查调用(单独的X和Y移动)每个框架 - >总共3.2M碰撞检查。

我的几乎所有实体都有16x16像素的大小,我一直在研究实现四叉树或更简单的网格进行碰撞检测,这应该会使碰撞检查的数量下降很多。按网格我的意思是http://conkerjo.wordpress.com/2009/06/13/spatial-hashing-implementation-for-fast-2d-collisions/

但我不知道如何实现简单的网格。欢迎所有帮助。甚至有更好的方法可以强制实施这一点。

实体更新步骤。 我分别进行X / Y轴运动。因为我想在对角线碰撞时滑向实体。

  1. 水平移动实体

  2. 检查并处理碰撞

  3. 垂直移动实体

  4. 检查并处理碰撞

  5. 对所有实体重复1-4

  6. void Entity::updateCurrent(sf::Time dt, CommandQueue& commands)
    {
        setPreviousPosition(getPosition());
        move(sf::Vector2f(mVelocity.x, 0) * dt.asSeconds());
        handleCollision();
        setPreviousPosition(getPosition());
        move(sf::Vector2f(0, mVelocity.y) * dt.asSeconds());
        handleCollision();
    }
    

    在我尝试同时处理X和Y移动之前,我遇到了以下问题: enter image description here

    我不知道我是否应该在碰撞后重置X或Y位置。

    碰撞处理。 我只会在实体移动时处理碰撞(目前只有角色实体,后来的投射物和一些特殊的瓷砖)

    1. if entity is tile - >什么都不做

    2. 如果实体是字符 - >检查与角色和瓷砖的碰撞,并在碰撞发生时重置移动

    3. void Entity::handleCollision()
      {
          if (getCategory() & Category::Tile)
              return;
          if (getCategory() & Category::Character)
          {
              std::set<SceneNode::Pair> collisionPairs;
              checkCollision(*mSceneGraph, collisionPairs);
      
              for (SceneNode::Pair pair : collisionPairs)
              {
                  if (matchesCategories(pair, Category::Character, Category::NonPassableCharacterOrTile))
                  {
                      resetPreviousPosition();
                      break;
                  }
              }
          }
      }
      

      我只需使用SFML的intersects-function来检查碰撞。这对于这个来说是否足够好?

      bool collision(const SceneNode& l, const SceneNode& r)
      {
          return l.getBoundingRect().intersects(r.getBoundingRect());
      }
      

      如果我要实现网格或四叉树进行碰撞检测,何时应该填充它,何时更新?我应该每次移动一个实体时更新它,还是应该尝试一次移动所有实体,然后构建网格/四叉树,然后才尝试处理所有碰撞。

      所以我的问题是(1)在这种情况下,我应该如何以及何时进行碰撞处理?我当前的实现工作正常,但我认为我经常这样做,所有我看到网格/四叉树的例子都假设我先做所有的动作,然后进行碰撞检测和处理。

      (2)何时清除/填充/更新我的网格/四叉树。例如,如果我有3600个瓷砖和3个移动字符。每次在网格中移动并尝试将其移动到不同的网格单元/树分支时,我应该寻找实体吗?

      编辑:

      除非有人提出更好的建议,否则我接下来会尝试下一步

      更新了更新步骤。 这样聪明还是以合理的方式做到这一点?

      1. 从grid / quadtree中删除实体

      2. 水平移动实体

      3. 将实体添加到grid / quadtree

      4. 检查并处理碰撞

      5. 从grid / quadtree中删除实体

      6. 垂直移动实体

      7. 将实体添加到grid / quadtree

      8. 检查并处理碰撞

      9. 对所有实体重复1-8

      10. Entity::move()
        {
            grid.getCell(getPosition()).remove(this);
            ... move x
            grid.getCell(getPosition()).add(this);
            ... if collision, reset x
        
            grid.getCell(getPosition()).remove(this);
            ... move y
            grid.getCell(getPosition()).add(this);
            ... if collision, reset y
        }
        
        Entity::checkCollision()
        {
            list<Entity*> possibleColliders;
        
            possibleColliders = grid.getEntitiesInRectangle(x - s, y - s, x + s, y + s);
        
           ... now only check collision against possibleColliders
        }
        

1 个答案:

答案 0 :(得分:-1)

我认为四叉树可以很好地工作,因为它将是独立的,将它添加到您当前的系统中确实没有问题。

您要问的重要问题可能是何时填充和更新四叉树。我认为这在很大程度上取决于您的用例。由于您有大约400个字符可以更改每个帧的位置,因此如果您尝试移动四叉树中的节点或完全重建四叉树,则可能不会产生很大差异。哪个性能更高,取决于您的算法和数据结构,这需要进行一些性能测试。

this tutorial中,他们还建议每帧迭代重建四叉树。

对于“如何修复碰撞处理”,您需要提供更多信息/单独的SO问题,因为问题不明确是什么。