2013-04-13 65 views
0

我有一個非常簡單的級別,其中包含一個靜態主體(以及相關的精靈)。當用戶觸摸身體時,我移除精靈,摧毀身體並用一個新的精靈替換爲動態身體,然後我轉換到新場景。我的代碼在第一次執行時完美運行,但是當這個場景重新加載時,它會在用戶觸及身體時崩潰。Box2D&Cocos2d級別重置問題

我在精靈的userData字段中存儲用於我的精靈的.png文件的文件名。然後,當用戶按下按鈕(觸摸身體)時,檢索它是一件簡單的事情。當我嘗試訪問精靈的userData字段時,隨後重新加載場景時會發生此問題。而不是保存文件名是空的(空)。當我嘗試使用文件名時,這又會使程序崩潰。

我不明白爲什麼它的作品第一次,而不是第二次。我設置了一個斷點並觀察文件名被分配到精靈的userData字段,但是它只在我第一次創建場景時纔可以檢索。這是ccTouchesBegan方法。崩潰發生在我嘗試分配newSpriteFileName的地方,因爲通過oldSpriteFileName的第二次運行是空的。

我剛剛對這個瘋了,但我相信它是明顯的東西。一如既往感謝您的幫助!

(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]; 
    } 
} 

}

回答

0

機會是,當你刪除精靈的NSString被釋放。爲什麼不把紋理名稱存儲在實例變量中?

+0

每個物體都有不同的紋理,因此每個精靈都有不同的文件名。我所做的解決上述問題的方法是創建我自己的CCSprite子類,並將NSString添加到我用於存儲值的類中。這就像一個冠軍,但我仍然不確定爲什麼它不能使用CCSprite所具有的userData。 – Scooter