Box2D - 在运行时创建主体时,主体不会发生碰撞

发布于 2025-01-08 13:35:07 字数 3494 浏览 0 评论 0原文

我一直在开发具有可破坏环境的游戏,并提出了一个解决方案,在该解决方案中检查 ContactListener 对象内是否存在可能的破坏。显然,因为这是在 Step() 内发生的,所以我将销毁处理推迟到该步骤之后的那一刻。我通过汇集需要在联系人监听器中处理的“破坏事件”来实现此目的,然后在 Step() 之后立即调用 contactListener->processDestructionEvents();

我这样做的方法是在 beginContact 事件中捕获碰撞灯具,然后确定撞击角度,然后使用该角度在灯具本身上进行光线投射。然后,我从夹具的 b2PolygonShape 中抓取顶点,然后生成两个新形状,这两个形状根据光线的撞击点和退出点进行分割。物体上的原始夹具被破坏,然后为第一个新形状生成新的夹具并将其添加到原始物体上。对于第二个形状,会生成一个新主体,并将该形状添加到这个新主体中。

不管怎样,一切都很好,在调试视图中我可以看到新的形状已经生成并且都已就位,正如它们应该的那样。然而,此时我的行为真的很糟糕。一旦这个过程完成,原始物体和新生成的物体都不会与任何东西发生碰撞。如果我启用连续物理,有时动态对象会与这些物体/装置的边缘之一发生碰撞,但并非总是如此。我想知道我在运行时重建主体/装置的方法是否做错了。这是生成新对象的代码,任何帮助将不胜感激。

void PhysicsContactListener::processDestructionEvents() {
   if(!hasDestructionEvents) {return;}

   for(destructionEventsIterator = destructionEvents.begin(); destructionEventsIterator != destructionEvents.end(); ++destructionEventsIterator) {

      b2Filter f1, f2;
      f1.groupIndex = destructionEventsIterator->originalFixture->GetFilterData().groupIndex;
      f1.categoryBits = destructionEventsIterator->originalFixture->GetFilterData().categoryBits;
      f1.maskBits = destructionEventsIterator->originalFixture->GetFilterData().maskBits;

      f2.groupIndex = destructionEventsIterator->originalFixture->GetFilterData().groupIndex;
      f2.categoryBits = destructionEventsIterator->originalFixture->GetFilterData().categoryBits;
      f2.maskBits = destructionEventsIterator->originalFixture->GetFilterData().maskBits;

      b2PolygonShape newShape0 = destructionEventsIterator->newFixtures[0];

      b2FixtureDef fixture0Def;
      fixture0Def.shape = &newShape0;
      fixture0Def.density = 1.0f;
      fixture0Def.restitution = 0.2f;

      b2Fixture* fixture1 = destructionEventsIterator->hostBody->CreateFixture(&fixture0Def);
      fixture1->SetFilterData(f1);
      //destructionEventsIterator->hostBody->SetAwake(true);
      destructionEventsIterator->hostBody->ResetMassData();
      //destructionEventsIterator->hostBody->SetActive(true);
      destructionEventsIterator->hostBody->SetTransform(destructionEventsIterator->hostBody->GetPosition(), destructionEventsIterator->hostBody->GetAngle());

      b2BodyDef bd;
      bd.position = destructionEventsIterator->hostBody->GetPosition();
      bd.angle = destructionEventsIterator->hostBody->GetAngle();
      bd.type = destructionEventsIterator->hostBody->GetType();

      b2Body* newBody = destructionEventsIterator->hostBody->GetWorld()->CreateBody(&bd);
      b2PolygonShape* newShape1 = (b2PolygonShape*)(&destructionEventsIterator->newFixtures[1]);
      b2Fixture* fixture2 = newBody->CreateFixture(newShape1, destructionEventsIterator->hostBodyDensity);
      fixture2->SetFilterData(f2);
      newBody->SetAngularVelocity(destructionEventsIterator->hostBody->GetAngularVelocity());
      newBody->SetLinearVelocity(destructionEventsIterator->hostBody->GetLinearVelocity());
      //newBody->SetAwake(true);
      newBody->ResetMassData();
      //newBody->SetActive(true);
      newBody->SetTransform(destructionEventsIterator->hostBody->GetPosition(), destructionEventsIterator->hostBody->GetAngle());

      destructionEventsIterator->hostBody->DestroyFixture(destructionEventsIterator->originalFixture);

   }

I've been working on a game with destructible environments and I've come up with a solution where I check for possible destruction within my ContactListener object. Obviously because this is taking place within Step(), I postpone processing the destruction until the moment after the step. I do this by pooling "destruction events" that need to be processed within the contact listener, and then immediately after Step() calling something like contactListener->processDestructionEvents();.

The way I do this is by capturing the colliding fixtures within the beginContact event and then determining the angle of impact, then using that angle to raycast on the fixture itself. I then grap the vertices from the b2PolygonShape of the fixture, then generate two new shapes which are split based on the impact and exit points of the ray. The original fixture is destroyed on the body, and then a new fixture is generated for the first new shape and added to the original body. For the second shape, a new body is generated and that shape is added to this new body.

Anyway everything works great, in debug view I can see that the new shapes have been generated and are all in place, as they should be. However, I get really screwed up behavior at this point. As soon as this process is complete, neither the original nor the newly generated body will collide with anything. If I enable continuous physics, SOMETIMES a dynamic object will collide with one of the edges of these bodies/fixtures, but not always. I'm wondering if it's something I'm doing wrong in my approach to rebuilding bodies/fixtures at runtime. Here is the code for generating the new objects, any help would be greatly appreciated.

void PhysicsContactListener::processDestructionEvents() {
   if(!hasDestructionEvents) {return;}

   for(destructionEventsIterator = destructionEvents.begin(); destructionEventsIterator != destructionEvents.end(); ++destructionEventsIterator) {

      b2Filter f1, f2;
      f1.groupIndex = destructionEventsIterator->originalFixture->GetFilterData().groupIndex;
      f1.categoryBits = destructionEventsIterator->originalFixture->GetFilterData().categoryBits;
      f1.maskBits = destructionEventsIterator->originalFixture->GetFilterData().maskBits;

      f2.groupIndex = destructionEventsIterator->originalFixture->GetFilterData().groupIndex;
      f2.categoryBits = destructionEventsIterator->originalFixture->GetFilterData().categoryBits;
      f2.maskBits = destructionEventsIterator->originalFixture->GetFilterData().maskBits;

      b2PolygonShape newShape0 = destructionEventsIterator->newFixtures[0];

      b2FixtureDef fixture0Def;
      fixture0Def.shape = &newShape0;
      fixture0Def.density = 1.0f;
      fixture0Def.restitution = 0.2f;

      b2Fixture* fixture1 = destructionEventsIterator->hostBody->CreateFixture(&fixture0Def);
      fixture1->SetFilterData(f1);
      //destructionEventsIterator->hostBody->SetAwake(true);
      destructionEventsIterator->hostBody->ResetMassData();
      //destructionEventsIterator->hostBody->SetActive(true);
      destructionEventsIterator->hostBody->SetTransform(destructionEventsIterator->hostBody->GetPosition(), destructionEventsIterator->hostBody->GetAngle());

      b2BodyDef bd;
      bd.position = destructionEventsIterator->hostBody->GetPosition();
      bd.angle = destructionEventsIterator->hostBody->GetAngle();
      bd.type = destructionEventsIterator->hostBody->GetType();

      b2Body* newBody = destructionEventsIterator->hostBody->GetWorld()->CreateBody(&bd);
      b2PolygonShape* newShape1 = (b2PolygonShape*)(&destructionEventsIterator->newFixtures[1]);
      b2Fixture* fixture2 = newBody->CreateFixture(newShape1, destructionEventsIterator->hostBodyDensity);
      fixture2->SetFilterData(f2);
      newBody->SetAngularVelocity(destructionEventsIterator->hostBody->GetAngularVelocity());
      newBody->SetLinearVelocity(destructionEventsIterator->hostBody->GetLinearVelocity());
      //newBody->SetAwake(true);
      newBody->ResetMassData();
      //newBody->SetActive(true);
      newBody->SetTransform(destructionEventsIterator->hostBody->GetPosition(), destructionEventsIterator->hostBody->GetAngle());

      destructionEventsIterator->hostBody->DestroyFixture(destructionEventsIterator->originalFixture);

   }

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

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

发布评论

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

评论(1

无所谓啦 2025-01-15 13:35:07

两块不会互相碰撞吗?看一下每个灯具最终的categoryBits 和maskBits 值 - 看起来每个部件都被赋予了相同的值。我的猜测是,您只是忽略了这样一个事实:这些掩码是双向检查的,例如。来自 Box2D 源代码:

bool collide =
      (filterA.maskBits & filterB.categoryBits) != 0 &&
      (filterA.categoryBits & filterB.maskBits) != 0;

另一方面,如果你的意思是这些碎片根本没有发生碰撞,并且只是从地面上掉下来,永远向下(除了有时),那么我可能会怀疑多边形缠绕不正确。

顺便说一句,b2Filter 仅包含基元,因此您可以直接分配它们:

b2Filter f1 = destructionEventsIterator->originalFixture->GetFilterData();

...而且,第一个 SetTransform 和第二个 ResetMassData 是多余的。

The two pieces don't collide with each other? Take a look at the categoryBits and maskBits values that each fixture ends up with - looks like each piece is given the same values for these. My guess is you are just overlooking the fact that these masks are checked against each other both ways, eg. from the Box2D source code:

bool collide =
      (filterA.maskBits & filterB.categoryBits) != 0 &&
      (filterA.categoryBits & filterB.maskBits) != 0;

On the other hand if you mean the pieces collide with nothing at all and simply fall through the ground and down forever except for SOMETIMES, then I might suspect an incorrect polygon winding.

btw a b2Filter holds only primitives so you could assign those directly:

b2Filter f1 = destructionEventsIterator->originalFixture->GetFilterData();

...also, the first SetTransform and the second ResetMassData are redundant.

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