2

我有多个带有物理实体的精灵。用户一次移动一个精灵。创建一个鼠标关节来支持移动。使用 Cocos2d V2.0

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

界面内

b2World* world;             
GLESDebugDraw *m_debugDraw; 

b2MouseJoint *mouseJoint;
b2Body* groundBody;              

float _boxHeight;
float _boxWidth;
int sectionW;

b2MouseJoint *m_mouseJoint;

执行

我大部分时间都在 TOUCHES ENDED 中的上面一行得到一个 EXC_BAD_ACCESS,xcode 在线程 Thread 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;
    };
4

5 回答 5

0

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

我承认,我正在尝试用鼠标关节解决完全相同的错误,所以我希望在这里找到答案。所有迹象都指向在我调用 DestroyJoint 之前被其他操作删除的关节,以便处理空指针,因此如果MouseJoint不是 nil 但mouseJoint 是,那么它可能会解释你的情况下的错误。

于 2012-09-16T02:38:46.857 回答
0

我正在从事的当前项目也有同样的问题。每次我试图破坏一个附有 mouseJoint 的身体时,我都会遇到程序崩溃(exC_BAD_ACCESS in touchesEnded:)。

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

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

Box2d 确实会在它们被破坏时破坏附着在身体上的关节。但是,我猜 Box2d 在通过 DestroyJoint 销毁关节指针后不会使其无效?

无论如何,我防止程序崩溃的方法是在我的 body 销毁函数中,我首先销毁了 mouseJoint(并将其设置为 NULL),然后再销毁 body。我用于销毁主体的代码(如果附加到要删除的主体,则首先删除 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* 只是我用来处理演员的 UIImageView 的一个子类。

于 2012-12-25T02:02:32.560 回答
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;
    }
}
于 2012-09-16T16:28:48.590 回答
0

I'll add some suggestions to check. I'm using box2d in libGDX. Both body and joint must be destroyed by world.destroyBody() and world.destroyJoint() accordingly. The order to destroy is the following:

  1. All joints
  2. All related bodies, not before 1!
  3. When all 1 & 2 destroyed, you may dispose world itself

And another thing to think of is the fact, that in box2d (libGDX's) mouseJoint is like the other joints has 2 bodies attached: bodyA & bodyB. But one of them is fictional - it may be any static body. I use fictional offscreen body. When deleting joints you may accidently remove that body. And all other joints may work well! But you'll indeed get exception when creating new joint, because of using badptr or null body, which is inexceptable. So, you must allways carefully destroy that fictional body. For example, you may add some MouseJointHelper class like:

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
};
于 2014-10-03T13:15:08.103 回答
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 来修复它。

于 2013-01-17T12:52:20.347 回答