2

物理体を持つ複数のスプライトがあります。ユーザーは一度に 1 つのスプライトを移動しています。動きをサポートするためにマウス ジョイントが作成されます。Cocos2d V2.0 の使用

マウス ジョイントは、QueryAABB(&callback, aabb) がフィクスチャを報告した後、ccTouchesBegan で初期化されます。Mouse Joint に関する 3 つのメソッド間のロジックの下

インターフェイス内

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 が接続されたボディを破棄しようとするたびに、プログラム クラッシュ (exc_BAD_ACCESS in touchesEnded:) が発生しました。

私の 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* は単にアクターを処理するために使用する 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

同じクラッシュエラーが発生しました:

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

そして、 **Other Linker Flags に -Obj**C フラグを追加して修正しました。

于 2013-01-17T12:52:20.347 に答える
0

ただのタイプミスではないですか?いくつかの場所ではmouseJointが表示され、他の場所ではMouseJointが表示されます。MouseJointをテストしますが、 mouseJointを破棄します。

認めますが、マウスの関節でまったく同じバグを解決しようとしているので、ここで答えを見つけたいと思っていました. すべての兆候は、DestroyJoint を呼び出す前に他の操作によって削除されたジョイントを指しているため、ヌル ポインターが処理 ます

于 2012-09-16T02:38:46.857 に答える