1

我正在使用 cocos2d 和 box2d,我有多达 5 个 b2body 需要同时销毁。它们都被添加到一个集合中std::set<b2Body*>row1RedArray;并由添加row1RedArray.insert(spriteBody);,并且我已经通过迭代删除了数组中的所有项目,但是当我在删除它们后触摸屏幕时,我的程序只是崩溃了。我是否正确地破坏了 b2Bodies?

//if that array is empty, then remove all objects from this array (row4)

if ((row4BlueArray.count == 0) && (row4.count >> 0) && (row4Removed == NO)) {
    std::set<b2Body *>::iterator pos04;
    for(pos04 = row4RedArray.begin(); pos04 != row4RedArray.end(); ++pos04) {
        b2Body *rowBody = *pos04;
        if (rowBody->GetUserData() != NULL)
        {
            for (CCSprite* sprite4 in row4) {
                [self removeChild:sprite4 cleanup:YES];
            }
            //Adding the b2Body to the toDelete Set and then removing it from the set of b2Bodies
            toDestroy.insert(rowBody);
            row4RedArray.erase(rowBody);
            row4Removed = YES;
        }
    }
}
std::set<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
    b2Body *body = *pos2;
    if (body->GetUserData() != NULL)
    {
       //Then removing the b2Body completely (this is all at the end of the tick method)
        _world->DestroyBody(body);
    }
}
4

2 回答 2

1

评论中船长 Obvlious 的解决方案是显而易见的,但并不正确。身体应该被 world->DestroyBody() 销毁。它需要简单地遍历主体,并通过调用此方法销毁每个主体(并且永远不要调用deleteb2Body、b2Fixture 或 b2Joint)。没有办法一次将它们全部摧毁。

于 2013-08-03T07:01:26.220 回答
0

你应该通过 world->DestroyBody() 销毁尸体,不要以任何其他方式处理它们。无法同时移除它们,但身体的移除必须在 box2d 世界步骤之外完成。这意味着如果您遍历您的列表并在下次更新 box2d 世界时销毁您想要的身体,那么看起来身体已经同时被处理掉了。

C++ 方面很少有可能导致未定义行为的问题。其中之一是在迭代容器时从容器中移除。在任何容器上使用擦除后,该容器的迭代器将变得无效。我建议的代码更少:

std::vector<b2Body *> toDestroy;
if ((row4BlueArray.count == 0) && (row4.count >> 0) && (row4Removed == NO)) 
{
    for(std::set<b2Body *>::iterator pos04 = row4RedArray.begin(); pos04 != row4RedArray.end(); ++pos04) 
    {
        b2Body *rowBody = *pos04;
        if (rowBody->GetUserData() != NULL)
        {
            toDestroy.push_back(rowBody);
            row4Removed = YES;
        }
    }

    for (CCSprite* sprite4 in row4) 
    {
        [self removeChild:sprite4 cleanup:YES];
    }
}

for( std::set<b2Body *>::iterator pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) 
{
    row4RedArray.erase( (*body) );
    _world->DestroyBody( (*body) );
}
//I have put the toDestroy vector in as a local variable so this is not needed, but if you     
//are having it as a member variable etc. you need to clear it before you are going to use 
//it in next loop, otherwise it will try to delete the same elements  a second time.
toDestroy.clear();

我不确定你为什么使用 std::set 来存储 b2Body 指针。集合通常比任何无序容器慢,比如我们的向量。我还从第二个 for 循环中删除了 if (rowBody->GetUserData() != NULL),当您将对象添加到 toDestroy 向量时进行检查时,可以假定对象通过了删除标准。

在遍历 row4 容器时,您还可以从场景中删除精灵(我从代码中假设它是某种容器),但您永远不会清除它。在您删除该容器中的所有元素后这样做可能是明智的,从我所见,这正在发生。您还尝试多次删除这些精灵,使用 for 循环中的“for (CCSprite* sprite4 in row4)”迭代主体,因此如果有一个以上的主体通过了要删除的条件,则再次遍历 row4 以删除精灵。

我不确定您为什么要根据“if (rowBody->GetUserData() != NULL) 标准”删除主体,但这可能是您在游戏中需要的东西,这在提供的代码中并不明显.

于 2013-08-03T08:50:49.933 回答