【问题标题】:Box2D - How can I know when 2 Fixtures are touching?Box2D - 我如何知道 2 个灯具何时接触?
【发布时间】:2012-03-12 16:17:55
【问题描述】:

我只是好奇,如果我的主体中有 2 个或更多未“连接在一起”的固定装置,我如何才能在代码中明确地确定这一点?这是我的意思的一个例子:

我标记了每个独特夹具的顶点,只是为了完全清楚这些是独立的形状,彼此不共享顶点。然而,它们被组合成一个整体。如您所见,两个灯具彼此非常接近或“接触”,其中一个是自行分开的。我想知道如何在 Box2D 中查询主体的固定装置,以便能够在运行时找到它。

为了全面了解这一切,它用于创建和处理可破坏的物体。该图像粗略地表示了在通过身体中的一组固定装置打孔后会发生什么。我需要查询哪些灯具相互接触,以便我可以将一个主体分成两部分,因为它们自然应该在那个点上。

【问题讨论】:

    标签: c++ box2d


    【解决方案1】:

    如果您已经准备好新的夹具,您可以使用 b2TestOverlap 函数检查它们是否重叠。该函数在 b2Collision.h 中找到:

    /// Determine if two generic shapes overlap.
    bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
                        const b2Shape* shapeB, int32 indexB,
                        const b2Transform& xfA, const b2Transform& xfB );
    

    可以通过fixture->GetShape()找到形状。索引参数仅用于指定要测试的链形状的哪一段,因此对于任何其他形状类型,您只需传入 0。由于固定装置在同一个主体上,最后两个参数都可以是 body-> GetTransform()。

    我自己从来没有使用过这个,所以我不能肯定地告诉你,但是请注意这个函数的名称是“重叠”,对于图中的 A 和 B 装置的情况,它可能不会返回正值因为从技术上讲,我不认为它们是重叠的。如果是这种情况,我认为您只能靠自己了,因为 Box2D 不提供任何“感人”测试。

    顺便说一句,Constantinius 提到的联系人列表仅对碰撞的不同物体上的灯具有效 - 同一物体上的灯具不会碰撞。

    【讨论】:

    • 谢谢,我认为它们没有碰撞,因为它们属于同一个物体。我会检查一下并回复你。我想我可能一个人在这里,但我会告诉你的。
    • 标记为正确,因为我独自一人。我最终不得不想出一些非常复杂的系统来判断一个主体何时应该将固定装置分成两个主体。忽略我之前的评论。笨手机和笨手机stackoverflow。
    • iforce2d,我如何确定用户的触摸是否“触摸”了 box2d 主体?
    • @marciokoko 您可以像测试平台一样使用 AABB 检查,在此处查看“MouseDown”功能:code.google.com/p/box2d/source/browse/trunk/Box2D/Testbed/…
    【解决方案2】:

    “9.3 访问联系人”下的Box2D manual中写着,你可以使用GetContactList函数访问一个body的所有联系人:

    for (b2ContactEdge* ce = myBody->GetContactList(); ce; ce = ce->next)
    {
        b2Contact* c = ce->contact;
        ...
    }
    

    b2ContactEdgeb2Contact 中,您可以找到实际的形状和标志(如果它们实际接触)(b2Contact::IsTouching)。

    【讨论】:

    • 谢谢,但正如 iforce 指出的那样,同一主体的固定装置不会发生碰撞。
    【解决方案3】:

    我建议这样做:

    • 要获得准确的结果,您确实必须测试交叉点。在第一遍中,您可以仅比较灯具的重心,然后仅在 COG 位于小距离内时计算所有线的交点。

    • 另一种方法可能是光栅化场景。然后你可以使用模板缓冲区之类的东西来绘制光栅化的像素。

    • 然后,模板将是一个大小为 (w*h) 的数组,其中 w 和 h 是光栅化图像的宽度和高度,每个像素保存一个整数。

    • 将模板缓冲区初始化为每个像素为 0。

    • 对于您“绘制”的每个光栅化夹具,您只需增加其所有像素位置的缓冲区值。

    • 所以最后,模板缓冲区在未被任何夹具占用的位置包含 0,在只有一个夹具位于该位置的位置包含 1,并且对于任何更大的值,您都有交叉点。

    这种方法的复杂性主要取决于所选的光栅化分辨率。

    【讨论】:

    • 谢谢 我曾想过光栅化过程,但没有那么深入。不确定我是否会使用它,但我会告诉你的。
    【解决方案4】:

    另一种方法是使用b2CollidePolygons 函数(来自b2Collision.h)。您可以在灯具的多边形形状上使用它,然后查看b2ManifoldpointCount 字段是否大于零。

    这里有一些示例 pre-C++11 代码(我还没有编译和测试,所以希望不会太 foobar'ed):

    bool isTouching(const b2PolygonShape& polygonA, const b2Transform& xfA, const b2PolygonShape& polygonB, const b2Transform& xfb)
    {
        b2Manifold manifold;
        b2CollidePolygons(&manifold, &polygonA, xfA, &polygonB, xfB);
        return manifold.pointCount > 0;
    }
    
    bool isPolygonFixturesTouching(const b2Fixture& fixtureA, const b2Fixture& fixtureB)
    {
        const b2Shape* shapeA = fixtureA.GetShape();
        const b2Shape* shapeB = fixtureB.GetShape();
        if (shapeA->GetType() == b2Shape::e_polygon && shapeB->GetType() == b2Shape::e_polygon)
        {
            const b2Body* bodyA = fixtureA.GetBody();
            const b2Transform& xfA = bodyA->GetTransform();
            const b2Body* bodyB = fixtureB.GetBody();
            const b2Transform& xfB = bodyB->GetTransform();
            return isTouching(*(static_cast<b2PolygonShape*>(shapeA)), xfA, *(static_cast<b2PolygonShape*>(shapeB)), xfB);
        }
        return false;
    }
    
    int main()
    {
        ...
        if (isPolygonFixturesTouching(fixtureA, fixtureB))
        {
            std::cout << "hooray!" << std::endl;
        }
    }
    

    注意: 我刚刚尝试过的一些粗略的计时测试比较 b2TestOverlapb2CollidePolygons 显示 b2TestOverlapb2CollidePolygons 快 4 或 5 倍。鉴于前者只寻找任何重叠,而后者正在计算碰撞流形,我想速度差异并不令人惊讶。无论如何,这个故事的寓意似乎是 b2TestOverlap 可能是更可取的功能,如果您只想知道 2 个固定装置是否正在接触,而b2CollidePolygons 更有用,如果您还想知道其他东西,比如如何两个固定装置正在接触。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-26
      • 1970-01-01
      • 2020-06-24
      • 2023-03-04
      • 2016-04-26
      • 2021-05-09
      相关资源
      最近更新 更多