touchesEnded上的world-> DestroyJoint(mouseJoint):EXC_BAD_ACCESS

时间:2012-09-16 00:36:24

标签: cocos2d-iphone box2d box2d-iphone

我有多个精神与物理机构。用户一次移动一个精灵。创建鼠标关节以支持移动。使用Cocos2d V2.0

在QueryAABB(& callback,aabb)报告夹具后,在ccTouchesBegan中初始化鼠标关节。下面三个方法之间的逻辑重新连接鼠标

在界面

b2World* world;             
GLESDebugDraw *m_debugDraw; 

b2MouseJoint *mouseJoint;
b2Body* groundBody;              

float _boxHeight;
float _boxWidth;
int sectionW;

b2MouseJoint *m_mouseJoint;

实施

我大部分时间都在TOUCHES ENDED上面的行上面有一个EXC_BAD_ACCESS,xcode在线程上显示以下内容 线程1

0 0x0000000
1 b2World::DestroyJoint(b2Joint*)
2 -[matchSprites ccTouchesEnded::withEvent
3 -[NSObject .... more lines reported

在上面的0步,它显示在右侧窗口中 错误:地址不包含指向目标文件中某个部分的部分

我已经按照目前提供的建议没有成功,此时看不出是什么产生了这个条件,经过测试我倾向于认为我破坏对象的方式导致了问题(即如果我禁用没有这种错误的代码就是破坏对象的代码。任何帮助将不胜感激。

以下完整代码

-(id) init
{
if( (self=[super init])) {

    self.isTouchEnabled = YES;

        // Load physics file
        [[GB2ShapeCache sharedShapeCache] addShapesWithFile:@"imagesphysics.plist"];

        // Add number images to cache
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"images.plist"];

        // init physics
        [self initPhysics];

        // Tags for the options are based on 500
        int numberOfOptions = 2;
        CGSize s = [CCDirector sharedDirector].winSize;

        sectionW = s.width / numberOfOptions;

        for (int i = 0; i < 2; i++) { 

            // Add target matching Sprites
            CCSprite *targetSprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"%d.png",i+1]];
            targetSprite.position = CGPointMake(i * sectionW + (sectionW/2.0)  ,s.height * 0.75); 
            [targetSprite runAction:[CCTintBy actionWithDuration:0.2f red:50 green:50 blue:40]];
            targetSprite.scale = 0.6f;
            [self addChild:targetSprite z:30 tag:i+1];

            // Add source matching physics sprites
            [self addNewSpriteAtPosition:CGPointMake(i * sectionW + (sectionW/2.0)  ,s.height * 0.35) number:i bodyType:b2_dynamicBody];
        }

        [self scheduleUpdate];
    }
    return self;
}

// Add Sprites

-(void) addNewSpriteAtPosition:(CGPoint)p number:(int)number bodyType:(b2BodyType)bodyType
{
    CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y);

    CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"%d.png",number+1]];
    sprite.scale = 0.6f;

    sprite.position = ccp(p.x,p.y);
    [self addChild:sprite z:35 tag:(number+1)+100];     

    // Define the dynamic body.
    b2BodyDef bodyDef;
    bodyDef.type = bodyType; 
    bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);

    bodyDef.userData = sprite;

    b2Body *body = world->CreateBody(&bodyDef);

    // Load the fixture using the vertices file generated by Physics Editor
    [[GB2ShapeCache sharedShapeCache] addFixturesToBody:body forShapeName:[NSString stringWithFormat:@"%d",number+1] forSprite:sprite];
    [sprite setAnchorPoint:
     [[GB2ShapeCache sharedShapeCache] anchorPointForShape:[NSString stringWithFormat:@"%d",number+1]]];

}

//Update the physics

    -(void) update: (ccTime) dt
    {

        int32 velocityIterations = 8;
        int32 positionIterations = 1;

        CGSize s = [CCDirector sharedDirector].winSize;

        world->Step(dt, velocityIterations, positionIterations);
        world->ClearForces();   

        // Store objects to be destroyed
        std::vector<b2Body *>toDestroy;

        CCSprite *currentSprite;
        CCSprite *targetSprite;
        int currentTag;

        for (b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {

            if (b->GetUserData() != NULL) {

                CCSprite *obj = (CCSprite*)b->GetUserData();
                obj.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
                obj.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());

                // Calculate the bounding box for this sprite
                _boxHeight = obj.boundingBox.size.height;
                _boxWidth = obj.boundingBox.size.width;

                currentSprite = (CCSprite *)b->GetUserData();
                currentTag = currentSprite.tag;
                targetSprite = (CCSprite *)[self getChildByTag:currentTag - 100];

                // SPECIFIC - matching sprite is tag + 100 of current userdata sprite for b object
                float distX = b->GetPosition().x * PTM_RATIO - targetSprite.position.x;
                float distY = b->GetPosition().y * PTM_RATIO - targetSprite.position.y; 

                if (distX * distX + distY * distY < (_boxWidth * _boxHeight) && b->GetType() == b2_dynamicBody) {
                    // Destroy object later
                    toDestroy.push_back(b);
                }

            } // if b-getuserdata

        }

        // Destroy objects

        std::vector<b2Body *>::iterator pos2;
        for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
            b2Body *body = *pos2;
            if (body->GetUserData() != NULL) {

                // Remove target matching
                CCSprite *sprite = (CCSprite *) body->GetUserData();
                currentTag = currentSprite.tag;
                targetSprite = (CCSprite *)[self getChildByTag:currentTag - 100];
                [self removeChild:sprite cleanup:YES];

                // Remove physics body associated with the Sprite
                world->DestroyBody(body);

    // This line has been commented  then test and the error persist!!!!
                    [self addNewSpriteAtPosition:CGPointMake(targetSprite.position.x  ,s.height * 0.75) number:targetSprite.tag-1 bodyType:b2_staticBody];
                }



        }

    }

//Init physics

-(void) initPhysics
{

    CGSize s = [[CCDirector sharedDirector] winSize];

    b2Vec2 gravity;
    gravity.Set(0.0f, -4.81f);
    world = new b2World(gravity);


    // Do we want to let bodies sleep?
    world->SetAllowSleeping(true);

    world->SetContinuousPhysics(true);

    m_debugDraw = new GLESDebugDraw( PTM_RATIO );
    //world->SetDebugDraw(m_debugDraw);

    uint32 flags = 0;
    flags += b2Draw::e_shapeBit;
            flags += b2Draw::e_jointBit;
            flags += b2Draw::e_aabbBit;
            //flags += b2Draw::e_pairBit;
            //flags += b2Draw::e_centerOfMassBit;
    m_debugDraw->SetFlags(flags);


    // Define the ground body.
    b2BodyDef groundBodyDef;
    groundBodyDef.position.Set(0, 0); // bottom-left corner

    // Call the body factory which allocates memory for the ground body
    // from a pool and creates the ground box shape (also from a pool).
    // The body is also added to the world.

    groundBody = world->CreateBody(&groundBodyDef);

    // Define the ground box shape.
    b2EdgeShape groundBox;

    // bottom

    groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));
    groundBody->CreateFixture(&groundBox,0);

    // top
    groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
    groundBody->CreateFixture(&groundBox,0);

    // left
    groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
    groundBody->CreateFixture(&groundBox,0);

    // right
    groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
    groundBody->CreateFixture(&groundBox,0);
}

//Touches handling

-(void)registerWithTouchDispatcher {

    [[[CCDirector sharedDirector] touchDispatcher] addStandardDelegate:self priority:0];
}

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (mouseJoint != NULL) return;

    UITouch *myTouch = [touches anyObject];
    CGPoint location = [myTouch locationInView:[myTouch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
    b2Vec2 p = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);

    // Make a small box.
    b2AABB aabb;
    b2Vec2 d;
    d.Set(0.001f, 0.001f);
    aabb.lowerBound = p - d;
    aabb.upperBound = p + d;

    // Query the world for overlapping shapes.
    QueryCallback callback(p);
    world->QueryAABB(&callback, aabb);

    if (callback.m_fixture)
    {
        b2Body* body = callback.m_fixture->GetBody();
        b2MouseJointDef md;
        md.bodyA = groundBody;
        md.bodyB = body;
        md.target = p;
        md.maxForce = 1500.0f * body->GetMass();

        mouseJoint = nil;
        mouseJoint = (b2MouseJoint*)world->CreateJoint(&md);
        pointer = &mouseJoint;
        NSLog(@"Pointer: %p", *pointer);
        //mouseJoint = (b2MouseJoint*)world->CreateJoint(&md);
        body->SetAwake(true);
    }
    [self ccTouchesMoved:touches withEvent:event];
}

-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (mouseJoint == NULL) return;

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL: location];
    b2Vec2 locationWorld = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);

    mouseJoint->SetTarget(locationWorld);

}

-(void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (mouseJoint) {
        world->DestroyJoint(mouseJoint);  // TODO INVESTIGATE WHY THIS CAUSES A BAD ACCESS ERROR
        mouseJoint = nil;

    }
}

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{


    if (mouseJoint) {

        //CCLOG(@"WORLD is nil %d",world != nil);
        //CCLOG(@"MOUSEJOINT is nil %d",mouseJoint != nil);

        NSLog(@"Pointer: %p", *pointer);

        mouseJoint->SetTarget(b2Vec2_zero);
        world->DestroyJoint(mouseJoint);  // TODO INVESTIGATE WHY THIS CAUSES A BAD ACCESS ERROR
        mouseJoint = NULL;
        CCLOG(@"MOUSE JOINT WAS DESTROYED SUCCESSFULLY!!!!!");
    }
}

//Query Callback


    class QueryCallback : public b2QueryCallback
    {
    public:
        QueryCallback(const b2Vec2& point)
        {
            m_point = point;
            m_fixture = NULL;
        }

        bool ReportFixture(b2Fixture* fixture)
        {
            b2Body* body = fixture->GetBody();
            if (body->GetType() == b2_dynamicBody)
            {
                bool inside = fixture->TestPoint(m_point);
                if (inside)
                {
                    m_fixture = fixture;

                    // We are done, terminate the query.
                    return false;
                }
            }

            // Continue the query.
            return true;
        }

        b2Vec2 m_point;
        b2Fixture* m_fixture;
    };

5 个答案:

答案 0 :(得分:0)

你确定这不只是一个错字吗?我在某些地方看到 mouseJoint ,在其他地方看到 MouseJoint 。您测试 MouseJoint ,但是您销毁 mouseJoint

我承认,我正试图用鼠标联合解决完全相同的错误,所以我希望在这里找到答案。在我调用DestroyJoint之前,所有符号都指向一个被其他操作删除的关节,以便处理空指针,因此如果 MouseJoint 不是nil而是 mouseJoint 那么它可能会解释您案件中的错误。

答案 1 :(得分:0)

我试图解决同样的问题。我在代码中有其他地方会在附加的精灵/身体被破坏时破坏鼠标关节等。原来你必须确保只在触摸事件中管理鼠标关节并将其余部分留给Box2D的。

你的代码中是否还有其他地方可能正在修改鼠标关节变量,比如在tick:方法中?

这是我触摸鼠标关节的唯一地方。它似乎也映射到您的用例。我使用的是LevelHelper事件代码,因此方法签名看起来有点不同。做到这一点大大简化了事情。

-(void)touchBegin:(LHTouchInfo*)info {
    CGPoint location = [[CCDirector sharedDirector] convertToGL: [info.touch locationInView: [info.touch view]]];
    _lastBrickTouched = info.sprite;
    _mouseJoint = [lh mouseJointForBody: _lastBrickTouched.body touchPoint: location];
}

-(void)touchMoved:(LHTouchInfo*)info{
    CGPoint touchZone = [info.touch locationInView:[info.touch view]];
    touchZone = [[CCDirector sharedDirector] convertToGL:touchZone];
    b2Vec2 p;
    p.Set(touchZone.x/PTM_RATIO, touchZone.y/PTM_RATIO);

    if (_mouseJoint != nil)
    {
        _mouseJoint->SetTarget(p);
    }
}

-(void)touchEnded:(LHTouchInfo*)info {
    if (_mouseJoint != nil) {
        world->DestroyJoint(_mouseJoint);
        _mouseJoint = nil;
    }
}

答案 2 :(得分:0)

我遇到了与我正在进行的当前项目相同的问题。每次我试图销毁附有mouseJoint的主体时,我都会遇到程序崩溃(touchesEnded中的EXC_BAD_ACCESS :)。

我的touchesEnded:代码与上面类似:

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 
{
    if (mouseJoint != NULL)
    {
        world->DestroyJoint(mouseJoint);
        mouseJoint = NULL;
    }
}

Box2d会破坏附着在身体上的关节。但是,我猜Box2d在通过DestroyJoint销毁之后不会使联合指针无效?

无论如何,我阻止程序崩溃的方式是在我的身体破坏功能中,我首先在销毁身体之前销毁了mouseJoint(并将其设置为NULL)。我的破坏物体的代码(如果附加到要删除的物体上,则首先删除mouseJoint)如下:

-(void)destroyActor:(ObjectView *)objectView
{
    b2Body* b = (b2Body*)objectView.tag;

    // Destroy mouseJoint if attached to body b

    b2JointEdge* jl = b->GetJointList();

    while (jl)
    {
        b2Joint* j = jl->joint;

        if (j == mouseJoint)
        {
            world->DestroyJoint(j);
            mouseJoint = NULL;
            break;
        }

        jl = jl->next;
    }

    world->DestroyBody(b);
    [objectView removeFromSuperview];
    [objectView release];
}

在我的代码中,ObjectView *只是我用来处理actor的UIImageView的子类。

答案 3 :(得分:0)

我遇到了同样的崩溃错误:

Thread 1, Queue : com.apple.main-thread
error: address doesn't contain a section that points to a section in a object file

我通过将 -Obj ** C标志添加到** Other Linker Flags 来修复它。

答案 4 :(得分:0)

我会添加一些建议来检查。我在libGDX中使用box2d。必须通过world.destroyBody()和world.destroyJoint()相应地销毁body和joint。销毁的顺序如下:

  1. 所有关节
  2. 所有相关机构,而不是1之前!
  3. 当所有1&amp; 2被摧毁,你可以自己处置世界
  4. 另一件需要考虑的事实是,在box2d(libGDX&#39; s)中,mouseJoint就像其他关节有2个身体一样:bodyA&amp; amp; bodyB。但其中一个是虚构的 - 它可能是任何静态的身体。我使用虚构的屏幕外体。删除关节时,您可能会意外删除该身体。所有其他关节都可以正常工作!但是在创建新关节时你确实会遇到异常,因为使用了badptr或null body,这是不可接受的。所以,你必须小心翼翼地摧毁那个虚构的身体。例如,您可以添加一些MouseJointHelper类,如:

    class MouseJointHelper
    {
      Body fictionalBody;
    
      MouseJoint createJoint(...) //here we create joint, using fictional body
      void destroyJointAndBodies(MouseJoint joint) //destroy joint and bodyA, assuming that bodyB is the same for all (fictional body)
      void dispose() //in destructor method destroy fictional body
    };