【问题标题】:EXC_BAD_ACCESS in Box2D with CreateFixture in iOSBox2D 中的 EXC_BAD_ACCESS 与 iOS 中的 CreateFixture
【发布时间】:2017-05-02 17:42:06
【问题描述】:

5-6 年来,我在 AppStore 上有多个使用 Cocos2D 和 Box2D 的游戏。我从来没有遇到过任何崩溃的问题。 Apple 让我更新它们,否则它们将被从 AppStore 中删除。所以我开始通过更新 Cocos2d 和 Box2d 来更新它们。在处理构建错误几个小时后,我可以测试了。我在模拟器中测试了跨越不同操作系统版本的 6 台设备。我还在我的 iPhone6 10.3 上进行了测试。我什至制作了不同尺寸的屏幕抓取。我将存档上传到 TestFlight,然后在我的设备上进行了测试.... CRASH。然后我回去在模拟器和 CRASH 上进行测试。现在它每次都在同一点崩溃。我不知道为什么它工作了这么久,现在没有任何代码更改。

我在 CreateBody 上遇到了崩溃。然后我将所有代码移到 world->Step 之后,现在它在 CreateFixture 上崩溃。我启用了僵尸,但这并没有给我更多的洞察力。

游戏开始,它创建了 2 个 b2Body 对象和 2 个 b2Fixture 对象(一个大环)。还有另一个可以上下移动的 b2Body 和 b2Fixture(飞艇)。目的是让飞艇穿过环。环从右向左移动。一旦您通过或未通过该环,环部件将被破坏并创建新环(2 b2Bodies 和 2 b2Fixtures)。第二个环是崩溃发生的地方。 (同样,多年来,从 ios 4.3 -> 10 开始,它一直运行良好),但现在尝试用 XCode 8 更新它不起作用(即使我测试了几个小时,昨天它运行良好)。

这里是环创建代码:(4-5年前我学习Box2D时写的)

-(void)addRing{

int r = (arc4random() % 250) + 160;
CGPoint p = ccp(SCREEN_WIDTH+100,r);

ring_bottom = [CCSprite spriteWithFile:@"ring_bottom.png"];
[self addChild:ring_bottom z:BLIMP_BOTTOM tag:bTagRingBottom];
ring_bottom.position = ccp(p.x, p.y);

// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(p.x/PTM_RATIO,p.y/PTM_RATIO);
bodyDef.userData = ring_bottom;
bodyDef.fixedRotation=YES;
bodyDef.gravityScale=0;
//bodyDef.position.Set(0.0, 0.1);
_ringBottom = _world->CreateBody(&bodyDef);

b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(0.25, 10.0, b2Vec2(0.0,13.00), 0.0);

// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 10.0f;
fixtureDef.friction = 0.0f;
fixtureDef.isSensor = true;

_ringBottom->CreateFixture(&fixtureDef);

//----------------------------------------------------

ring_top = [CCSprite spriteWithFile:@"ring_top.png"];
[self addChild:ring_top z:GAME_LAYER tag:bTagRingTop];
ring_top.position = ccp(p.x, p.y);

// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef2;
bodyDef2.type = b2_dynamicBody;
bodyDef2.position.Set(p.x/PTM_RATIO,p.y/PTM_RATIO);
bodyDef2.userData = ring_top;
bodyDef2.fixedRotation=YES;
bodyDef2.gravityScale=0;
_ringTop = _world->CreateBody(&bodyDef2);

b2PolygonShape dynamicBox2;
dynamicBox2.SetAsBox(0.25, 10.0, b2Vec2(0.0,-13.00), 0.0);

// Define the dynamic body fixture.
b2FixtureDef fixtureDef2;
fixtureDef2.shape = &dynamicBox2;
fixtureDef2.density = 10.0f;
fixtureDef2.friction = 0.0f;
fixtureDef2.isSensor = true;

_ringTop->CreateFixture(&fixtureDef2);
}

如果我注释掉 CreateFixture,它运行得非常好。我做不到。

崩溃在 b2Body.cpp 中:

b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
{

...

fixture->Create(allocator, this, def);

...

}

在 b2Fixture.cpp 中

void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def)
{

...

m_shape = def->shape->Clone(allocator);

...

}

我有 5-6 个使用 Box2d 和 Cocos2d 的应用程序,我不想将它们从 AppStore 中删除,但我也无法重新开始使用它们。我已经写了一个版本,创建发生在 world->Step 之后,但这并没有改变任何东西,仍然崩溃。

这是在 tick 方法中删除正文的代码:

std::vector<b2Body *>toDestroy;

...

std::vector<b2Body *>::iterator pos2;
    for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
        b2Body *body = *pos2;
        if (body->GetUserData() != NULL) {
            CCSprite *sprite = (CCSprite *) body->GetUserData();
            [self removeChild:sprite cleanup:YES];
        }
        _world->DestroyBody(body);
    }

希望有人可以帮助我避免这些游戏被从 AppStore 中删除。感谢您提供任何帮助,请记住,我已经很多年没有使用过 Box2d,所以坦率地说,我不太记得它了。

编辑: 我恢复到了旧版本的 Cocos2d,我又回到了 CreateBody 上的崩溃。更具体地说:

b2BlockAllocator.cpp

void* b2BlockAllocator::Allocate(int32 size){

...

    if (m_freeLists[index]){
        b2Block* block = m_freeLists[index];
        m_freeLists[index] = block->next; <--------------CRASH
         return block;
    } else {

     ...

    }
}

我总是在索引 6 上崩溃

> Printing description of this->m_freeLists:
(b2Block *[14]) m_freeLists = {
  [0] = 0x0000000000000000
  [1] = 0x0000000103ca4060
  [2] = 0x0000000103ca0080
  [3] = 0x0000000100b30120
  [4] = 0x0000000000000000
  [5] = 0x0000000103ca80a0
  [6] = 0x0000000300b2c180
  [7] = 0x0000000104240000
  [8] = 0x0000000000000000
  [9] = 0x000000010423c140
  [10] = 0x0000000000000000
  [11] = 0x0000000000000000
  [12] = 0x0000000000000000
  [13] = 0x0000000000000000
}

所以块中的下一个是空的,所以它崩溃了。另一个论坛说,一个代码非常相似的人试图多次破坏同一个对象。我没有看到这种情况发生。

【问题讨论】:

  • 在最后一组代码中,您是否删除了迭代器当前指向的项目?如果是这样,那么您的迭代器将被无效,因此在不调用未定义行为的情况下无法递增它。
  • 如果是这样的话,这似乎永远不会奏效。我刚刚注意到的一件事是,如果您成功通过了游戏中的第一个环,它会在销毁旧环之前调用 addRing 并在 Destroy 之前崩溃。我不确定 Destroy 是否是问题所在。
  • 如果是这样的话,这似乎永远不会奏效——“未定义的行为”意味着——行为未定义。这包括看起来工作正常。直到现在您才看到问题(如果问题正在增加无效的迭代器)。
  • 你是说它在尝试销毁时崩溃?如果 Destroy 是问题,那么 CreateFixture 代码中会发生异常吗?如果是这样,这如何适应在调用 Destroy 之前崩溃?
  • 我只是在查看您发布的代码。由于您没有提供minimal reproducible example,我不知道何时、何地或如何调用您的例程。我的意思是,如果您以这种方式编写了一个循环,您使用迭代器递增到下一个项目,如果迭代器(在本例中为 pos2)指向您刚刚的项目删除,执行++pos2 是未定义的行为,因为迭代器已失效。从向量中删除项目的安全方法(我不知道方括号中的内容是什么意思)是使用erase / remove_if,从而消除编写循环。

标签: c++ ios cocos2d-iphone xcode8 box2d


【解决方案1】:

因此,正如 PaulMcKenzie 指出的那样,问题在于我破坏尸体的方式。这最初是为 Xcode 4.3 编写的,现在更新为 Xcode 8.3 我遇到了崩溃问题。我不再了解 Box2D,所以我快速修复了 Destroying the fixtures 并隐藏 sprite,然后在它们离开屏幕后销毁身体。这似乎对我现在有用,因为我不能花时间用 (erase(remove_if()) 修复它,正确的方法,它现在就可以了。

我正在回答这个问题,因为这是位于 tick 方法中的违规代码:

std::vector<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
    b2Body *body = *pos2;
    if (body->GetUserData() != NULL) {
        CCSprite *sprite = (CCSprite *) body->GetUserData();
        [self removeChild:sprite cleanup:YES];
    }
    _world->DestroyBody(body);
}

重要的是要以正确的方式重写它以销毁 b2Body。

如果有人写出破坏尸体的正确方法,我会将其标记为正确答案。

【讨论】:

  • 我同意似乎正在发生内存损坏。如果您只是从迭代代码(而不是整个块)中注释掉 [self removeChild:sprite cleanup:YES] 会发生什么?或者只是注释掉_world-&gt;DestroyBody(body) 代码?崩溃有什么不同吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-16
  • 2012-09-21
  • 1970-01-01
  • 2014-02-27
  • 2012-07-30
  • 2011-04-10
  • 2012-09-16
相关资源
最近更新 更多