Box2D - 我如何知道 2 个灯具何时接触?

发布于 2025-01-07 14:12:00 字数 411 浏览 1 评论 0原文

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

具有超过 1 个固定装置的单个物体的示例,其中两个接触,一个不接触。

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

为了正确看待这一切,它是为了创建和处理可破坏的物体。该图像粗略地展示了在身体上的一组固定装置上打孔后会发生什么情况。我需要查询哪些固定装置相互接触,以便我可以将一个主体分成两个,因为此时它们自然应该如此。

I'm just curious, in the case that I have a body that has 2 or more fixtures in it that are not "joined together", how can I determine this definitively in code? Here is an example of what I mean:

Example of a single body with more than 1 fixture, two are touching, one is not.

I marked the vertices for each distinctive fixture just to make it completely clear that these are separate shapes which do not share vertices with each other. They are however combined into a single body. As you can see, two fixtures are within very close proximity to each other or "touching", and one is set apart by itself. I'm wondering how I can query the fixtures of a body in Box2D to be able to find this out at runtime.

In order to put this all into perspective, it's for creating and processing destructible bodies. The image is a rough representation of what will happen after a hole has been punched through a set of fixtures in a body. I need to query to see which fixtures touch each other so that I can split the one body into two, as naturally they should be at that point.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

幼儿园老大 2025-01-14 14:12:00

如果您已经准备好新的灯具,则可以使用 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-> ;获取变换()。

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

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

If you already have the new fixtures prepared you could use the b2TestOverlap function to check if they are overlapping. The function is found in 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 );

The shapes can be found by fixture->GetShape(). The index parameters are only used to specify which segment of a chain shape to test against, so for any other shape type you can just pass in 0. As the fixtures are on the same body, the last two parameters can both be body->GetTransform().

I have never used this myself so I couldn't tell you for sure, but noting that the name of this function is 'overlap', it may not return a positive for the case of your A and B fixtures in the diagram since technically I don't think they are overlapping. If this is the case, I think you are on your own because Box2D doesn't offer any 'touching' tests.

btw the contact list mentioned by Constantinius is only valid for fixtures on different bodies colliding - fixtures on the same body don't collide.

乱了心跳 2025-01-14 14:12:00

Box2D 手册中的“9.3 访问联系人”下写道,您可以使用函数 GetContactList 访问身体的所有触点:

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

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

In the Box2D manual under "9.3 Accessing Contacts" it is written, that you can access all contacts of a body using the function GetContactList:

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

In the b2ContactEdge and the b2Contact you can find the actual shapes and a flag if they are actually touching (b2Contact::IsTouching).

君勿笑 2025-01-14 14:12:00

我建议这样做:

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

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

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

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

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

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

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

I would suggest doing something like this:

  • to get an accurate result you really have to test for intersections. In a first pass you could compare only the centers of gravity of the fixtures and then only compute the intersections of all lines if the COGs lie within small distance.

  • another approach might be to rasterize the scene. then you could paint the rasterized pixels using something like a stencil buffer.

  • the stencil would then be an array of size(w*h) where w and h are width and height of your rasterized image and holds an integer per pixel.

  • initialize the stencil buffer with 0 for each pixel.

  • for each rasterized fixture that you 'paint' you just increment the buffer value for all of its pixel positions.

  • so finally the stencil buffer contains 0 at positions which are not occupied by any fixture, 1 where only one fixture lies at the position and for any greater value you have intersections.

the complexity of this approach then mainly depends on the chosen rasterization resolution.

日久见人心 2025-01-14 14:12:00

另一种方法(作为其他人之前建议的使用 b2TestOverlap 的替代方法)是使用 b2CollidePolygons 函数(来自 b2Collision.h)。您可以在灯具的多边形形状上使用它,然后查看 b2ManifoldpointCount 字段是否大于零。

这里有一些 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 显示 b2TestOverlap 速度快 4 或 5 倍(比b2CollidePolygons)。鉴于前者只是寻找任何重叠,而后者正在计算碰撞流形,我认为速度差异并不令人惊讶。无论如何,这个故事的寓意似乎是,如果您只想知道 2 个灯具是否接触,那么 b2TestOverlap 可能是更适合使用的函数,而 b2CollidePolygons 更有用如果您还想了解其他信息,例如两个灯具如何接触。

Another way to do this (as an alternative to using b2TestOverlap as suggested previously by someone else), would be to use the b2CollidePolygons function (from b2Collision.h). You would use this on the polygon shapes of the fixtures and then see whether the b2Manifold's pointCount field is greater than zero.

Here's some example pre-C++11 code for you (which I have not compiled and tested so hopefully isn't too 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;
    }
}

Note: Some crude timing tests which I've just tried that compare b2TestOverlap vs. b2CollidePolygons show b2TestOverlap to be 4 or 5 times faster (than b2CollidePolygons). Given that the former is only looking for any overlap while the later is calculating a collision manifold, I suppose the the speed difference isn't surprising. Anyways, it seems the moral of this story is that b2TestOverlap is likely the preferable function to use if you just want to know whether 2 fixtures are touching while b2CollidePolygons is the more useful if you also want to know additional stuff like how the 2 fixtures are touching.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文