0

単一の静的なボディ (および関連付けられたスプライト) を持つ非常に単純なレベルがあります。ユーザーがボディに触れると、スプライトを削除し、ボディを破棄して新しいスプライトを含むダイナミック ボディに置き換え、新しいシーンに遷移します。私のコードは、最初に実行されたときは完全に機能しますが、このシーンをリロードすると、ユーザーが体に触れるとクラッシュします。

スプライトに使用する .png ファイルのファイル名をスプライトの userData フィールドに保存します。次に、ユーザーがボタンを押す (ボディに触れる) と、それを取得するのは簡単なことです。スプライトの userData フィールドにアクセスしようとすると、その後のシーンのリロードで問題が発生します。ファイル名を保持する代わりに、空 (null) です。ファイル名を使用しようとすると、これによりプログラムがクラッシュします。

2回目ではなく1回目で機能する理由がわかりません。ブレークポイントを設定し、ファイル名がスプライトの userData フィールドに割り当てられるのを監視しますが、最初にシーンを作成するときにしか取得できません。これが ccTouchesBegan メソッドです。2 回目の実行で oldSpriteFileName が空であるため、newSpriteFileName を割り当てようとするとクラッシュが発生します。

私はこれに夢中になりましたが、それは明らかなことだと確信しています。いつも助けてくれてありがとう!!

    (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        for( UITouch *touch in touches )
        {
            CGPoint touchLocation = [touch locationInView: [touch view]];
            touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];

    touchLocation = [self convertToNodeSpace:touchLocation];
    b2Vec2 locationWorld = b2Vec2(touchLocation.x/PTM_RATIO, touchLocation.y/PTM_RATIO);

    NSLog(@"Location x = %f, y = %f", touchLocation.x, touchLocation.y);
    b2AABB aabb;
    b2Vec2 delta = b2Vec2(1.0/PTM_RATIO, 1.0/PTM_RATIO);
    aabb.lowerBound = locationWorld - delta;
    aabb.upperBound = locationWorld +delta;
    SimpleQueryCallback callback(locationWorld);
    m_world->QueryAABB(&callback, aabb);

    //If they have not pressed a button yet, and this touch was actually inside 
    //one of the buttons then we will destroy the static button (and sprite) 
    //that they touched and replace it with a dynamic button
    //(and new darker sprite) that falls, spinning off of the screen.
    if(!replaceButtonPushedYet && callback.fixtureFound)
    {
        //Get a reference to the static body of the button they touched and wake it up
        b2Body *body = callback.fixtureFound->GetBody();
        body->SetAwake(true);

        //Get the position of the body (button) they touched and use it to 
        //position the new button.  This value is in Box2D coordinates, 
        //so when I position the new button I won't divide by PTM_RATIO.
        b2Vec2 touchedButtonPosition = body->GetPosition();

        //Get the sprite from the button the user pressed
        CCSprite *bodySprite = (CCSprite*)body->GetUserData();

        //Then extract the file name of the sprite.  I assigned this to 
        //sprite's userData when I loaded the sprite in the method          //"placeTheIndividualButton".  Now I am going to extract it and 
        //then replace "(up)" with "(down)" in that string
        //and that becomes the name of the sprite for the new (pressed) 
        //button I am getting ready to create.  It is all about the file
        //naming conventions!
        NSString *oldSpriteFileName = (NSString*)bodySprite.userData;
        NSString *newSpriteFileName = [oldSpriteFileName stringByReplacingOccurrencesOfString:@"up" withString:@"down"];


        //First remove the sprite tied to the button the user pressed, 
        //then destroy the body of the button.
        [self removeChild:bodySprite cleanup:YES];
        body->GetWorld()->DestroyBody(body);

        //Set the bool to true to keep this code from executing again.  
        //This ensures that once they press a button they can't 
        //press another one.
        replaceButtonPushedYet = true;

        //Build the new dynamic button that will fall and spin off the screen
        b2BodyDef buttonBodyDef2;
        b2PolygonShape buttonShape2;
        b2FixtureDef buttonShapeDef2;
        b2Vec2 vertices2[4];

        //load the sprite for the second button (pressed down) and add it to the layer
        level_down = [CCSprite spriteWithFile:newSpriteFileName];
        level_down.userData=newSpriteFileName;
        [self addChild:level_down];

        //Define the polygon that forms the second button (pressed down)
        buttonBodyDef2.type = b2_dynamicBody;
        //Not dividing touchedButtonPosition.x or .y by PTM_RATIO because 
        //they are already in Box2D coordinates
        buttonBodyDef2.position.Set(touchedButtonPosition.x, touchedButtonPosition.y);
        buttonBodyDef2.angularVelocity = 1.5;
        buttonBodyDef2.userData = level_down;
        buttonBody2 = m_world->CreateBody(&buttonBodyDef2);

        //Define the vertices for the replacement button
        vertices2[0].Set(-94/PTM_RATIO, -32/PTM_RATIO);
        vertices2[1].Set(94/PTM_RATIO, -32/PTM_RATIO);
        vertices2[2].Set(94/PTM_RATIO, 32/PTM_RATIO);
        vertices2[3].Set(-94/PTM_RATIO, 32/PTM_RATIO);
        buttonShape2.Set(vertices2, 4);

        //Define the shape for the replacement button
        buttonShapeDef2.shape = &buttonShape2;
        buttonShapeDef2.density = 50.01f;
        buttonShapeDef2.friction = 0.75f;
        buttonShapeDef2.restitution = 0.1f;

        //The static buttons and the dynamic buttons are both in this groupIndex.  
        //Since it is a negative number they will never collide.  If it was 
        //positive they would always collide.
        buttonShapeDef2.filter.groupIndex = -1;

        //Put the second button (pressed down) into the world.
        buttonBody2->CreateFixture(&buttonShapeDef2);

        //This starts a timer that fires every second to call the makeTransition 
        //method.  The code inside that method will check to see if the button 
        //has fallen off the screen yet.  If it has then it will transition to 
        //the new selected level.
        //The colon after makeTransition sends a ccTime (dt).  I don't need it, 
        //but may in the future so I left it in there.
        buttonFalling = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(makeTransition:) userInfo:nil repeats:YES];
    }
}

}

4

1 に答える 1