当Box2D物体在时间步长之外被销毁时,联系侦听器崩溃

3
我正在使用box2d,并且有一些我正在销毁的物体(已经标记为需要删除),但是接触监听器仍然会崩溃,因为它得到了与这些物体相关的联系。
在接触监听器的presolve和begin contact方法中执行以下操作:
const b2Body* bodyA = contact->GetFixtureA()->GetBody();

const b2Body* bodyB = contact->GetFixtureB()->GetBody();

Object * objectA  = (Object*)bodyA->GetUserData();
Object * objectB  = (Object*)bodyB->GetUserData();

要么objectA,要么objectB 是指向无用的指针,因为该对象已从世界时间步中移除。看起来创建了错误的联系或者仍然存在的联系已经不应该存在。 更新 我已经更改了代码,确保验证正确的物体被销毁(及其容器物体),并发现接触侦听器仍在尝试处理不应存在的联系。我正在使用iOS/Xcode平台,启用NSZombie,确实发现接触体userdata是已经删除的对象(消息发送到已释放的实例)。检查Box2d源代码,我发现当物体被销毁时,接触确实被销毁了。我将不得不浏览更多Box2D代码或仅更改我的代码以避免侦听器收到的神秘接触。
当我测试将身体的userdata设置为null(同样,在世界步骤之外),我在接触侦听器中接收到的此身体的接触(在接触侦听器中检查时)并没有空的userdata。

你如何销毁对象?请展示代码。 - Pavel
身体被正确地销毁了(world->DestroyBody(body);)。我知道身体已被销毁,问题是旧的接触似乎没有在销毁身体时被移除,所以这些旧的接触通过接触侦听器传递,并引起问题。 - ajeetdl
1
world->DestroyBody会销毁所有的物体接触。在这里看一下它的代码:http://pastebin.com/cKJDfN6c(v2.2.1)。我认为,你可能搞混了什么(例如,销毁另一个物体)。 - Pavel
2个回答

1
根据我所看到的,Box2d物体的破坏与此无关。GetUserData返回您在创建物体时传递的任何内容,这可能是垃圾。您可能已经删除了它或者传递了null。如果您可以提供创建和破坏物体的代码,我可能能够告诉您更多信息。
如果物体无效,则程序可能会在以下位置崩溃:
contact->GetFixtureA()->GetBody();

或者是bodyB部分。

你是对的,当创建主体时,我将UserData设置为包含主体的Object。即,Object类包含一个成员b2Body * body。因此,该主体被分配给此对象,这就是为什么上面的代码期望GetUserData()返回一个Object对象(在这里命名非常糟糕,抱歉)。该Object确实被设置为被销毁,在事实上,对象的析构函数是DestroyBody(body)所在的位置。我的问题是,我不再希望此联系仍然存在,因为主体和用户数据已在步骤之外被删除。 - ajeetdl
这可能是一个愚蠢的问题,但你是否在调试模式下运行它,并且在box2d世界步骤之外调用了world->DestroyBody(body)?在调试模式下,如果您尝试在接触侦听器内调用world->DestroyBody(body),程序应该会断言,因为不允许在世界步骤中销毁box2d对象。在发布模式下,如果您尝试在世界步骤中销毁身体,则根本不会删除身体。因此,这意味着包装box2d身体的对象已被销毁,而身体和侦听器仍然存在于世界中。 - North-Pole
我没有在调试模式下运行,但是world->DestroyBody(body)是在世界步骤之外完成的——它是在世界步骤调用和ClearForces调用之后立即完成的。如果我像这样销毁一个物体,根据我的理解,该物体的所有联系也将被删除,这可能是一个错误的假设吗? - ajeetdl
谢谢你的帮助,不幸的是我几个小时内无法查看此问题。但至少现在我有东西可以研究了。我想知道如果是这种情况,为什么有时候即使调用world->DestroyBody(body),身体仍然没有被销毁。 - ajeetdl
1
很高兴能够帮忙。 我唯一能想到的原因是它在世界步骤中被破坏了,但你说这不是问题。另外一个可能是世界被锁定了,但我不知道为什么会在世界步骤之外发生这种情况。我会考虑一下。当你找出原因时,请告诉我。 - North-Pole
显示剩余5条评论

1
问题在于我创建了两个完全相同的刚体,而且不知情地将它们都传递了相同的用户数据。当第一个刚体与相应的用户数据(以及包含对象)一起被销毁时,第二个刚体仍在创建接触点,并且由于与刚体相关联的用户数据已被释放,我遇到了所描述的问题。
在删除之前将刚体的userdata设置为NULL似乎不起作用,因为当崩溃发生时,调试器实际上显示给我的是第二个刚体,它的用户数据还没有被设置为NULL。导致我花费了很长时间才找到它的原因是代码中有一个容器对象内部的继承结构,这使得很难发现正在创建两个刚体。
结果证明,这是一个无法仅通过我发布的代码解决的错误,因此尽管Tomasz和Pavel的答案没有帮助我解决问题,但我必须感谢他们至少尝试帮助。谢谢你们两个。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接