【问题标题】:c++ implementing collision detection and handling for tiled 2D world with smooth wall slidingc++为平铺的2D世界实现碰撞检测和处理,平滑的墙壁滑动
【发布时间】:2013-12-20 02:35:10
【问题描述】:

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

在最坏的情况下,大约 400 个字符四处移动,大约 3600 个图块,我有 4000 个可能发生碰撞的实体,每帧有 800 个碰撞检查调用(单独的 X 和 Y 移动)-> 总共 320 万次碰撞检查。

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

但我不知道我应该如何实现简单的网格。欢迎所有帮助。可能有更好的方法来强制执行此操作。

实体更新步骤。 我分别做 X/Y 轴移动。因为我想在对角碰撞时与实体滑动。

  1. 水平移动实体

  2. 检查和处理冲突

  3. 垂直移动实体

  4. 检查和处理冲突

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

.

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 运动时遇到过以下问题:

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

碰撞处理。 我只会在实体移动时处理碰撞(目前只有角色实体、后来的射弹和一些特殊图块)

  1. 如果实体是平铺 -> 什么也不做

  2. 如果实体是角色 -> 检查与角色和图块的碰撞,如果发生碰撞则重置移动

.

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 函数简单地检查碰撞。这大概够用了吧?

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

如果我要实现网格或四叉树来进行碰撞检测,我应该什么时候填充它,什么时候更新?我应该在每次移动一个实体时更新它,还是应该尝试想出一种方法来一次移动所有实体,然后构建网格/四叉树,然后才尝试处理所有冲突。

所以我的问题是:(1)在这种情况下,我应该如何以及何时进行碰撞处理?我目前的实现是可行的,但我认为我这样做太频繁了,我研究网格/四叉树的所有示例都假设我首先进行所有运动,然后进行碰撞检测和处理。

和(2)什么时候清除/填充/更新我的网格/四叉树。例如,如果我有 3600 个图块和 3 个移动角色。每次在网格中移动时我是否应该寻找实体并尝试将其移动到不同的网格单元/树枝?

编辑:

除非有人给出更好的建议,否则我接下来会尝试什么

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

  1. 从网格/四叉树中移除实体

  2. 水平移动实体

  3. 将实体添加到网格/四叉树

  4. 检查和处理冲突

  5. 从网格/四叉树中移除实体

  6. 垂直移动实体

  7. 将实体添加到网格/四叉树

  8. 检查和处理冲突

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

.

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
}

【问题讨论】:

  • 我认为你在这里问了太多问题。另外,您是否尝试过 gamedev 堆栈交换网站?
  • 我想这可以在两个单独的问题中提出:如何修复碰撞处理以及如何在其中添加网格/四叉树。我看过的所有示例都假设我想一次性处理所有碰撞。因此,我认为我的两个问题或多或少地相互影响。
  • 请注意:所有字符是否都意味着相互碰撞?瓷砖不应检查彼此之间的碰撞。这样,您将拥有更少的碰撞对,因为在大多数情况下即使不是所有移动角色都发生碰撞,您可以将数量减少一半或更少。跨度>
  • @NickL。目前,我拥有的所有角色实体都应该与之发生碰撞,并且不允许彼此穿过。我只在角色移动时检查碰撞。我一直在测试这个,主要是字符字符冲突

标签: c++ collision-detection quadtree


【解决方案1】:

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

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

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

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

【讨论】:

  • 该示例似乎也遵循以下顺序:1) 移动所有内容,2) 重建四叉树,3) 检测碰撞,4) 处理碰撞。如果实体移动由于碰撞而被重置怎么办?我需要再次重建四叉树并重复吗?这实际上是我的“如何修复碰撞处理”问题的一部分,因为目前我这样做:1)移动实体,2)检测碰撞,3)处理碰撞,4)对所有实体重复 1-3
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
相关资源
最近更新 更多