Cocos2d iphone Box2D&;Cocos2d级别重置问题

Cocos2d iphone Box2D&;Cocos2d级别重置问题,cocos2d-iphone,box2d,user-data,Cocos2d Iphone,Box2d,User Data,我有一个非常简单的关卡,里面有一个静态的身体(和相关的精灵)。当用户触摸身体时,我移除精灵,销毁身体,并用一个新精灵替换为一个动态身体,然后过渡到一个新场景。我的代码在第一次执行时工作得很好,但是当重新加载此场景时,当用户触摸身体时,它会崩溃 我将用于我的精灵的.png文件的文件名存储在精灵的userData字段中。然后,当用户按下按钮(触摸身体)时,检索它是一件简单的事情。当我尝试访问sprite的userData字段时,问题发生在随后的场景重新加载上。它不是保留文件名,而是为空(null)。

我有一个非常简单的关卡,里面有一个静态的身体(和相关的精灵)。当用户触摸身体时,我移除精灵,销毁身体,并用一个新精灵替换为一个动态身体,然后过渡到一个新场景。我的代码在第一次执行时工作得很好,但是当重新加载此场景时,当用户触摸身体时,它会崩溃

我将用于我的精灵的.png文件的文件名存储在精灵的userData字段中。然后,当用户按下按钮(触摸身体)时,检索它是一件简单的事情。当我尝试访问sprite的userData字段时,问题发生在随后的场景重新加载上。它不是保留文件名,而是为空(null)。当我尝试使用文件名时,这反过来会使程序崩溃

我不明白为什么第一次有效,第二次无效。我设置了一个断点并观察文件名被分配到sprite的userData字段,但它只有在我第一次创建场景时才可检索。以下是ccToucheSBegind方法。崩溃发生在我尝试分配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];
    }
}

}

移除精灵时,可能会释放
NSString
。为什么不将纹理名称存储在实例变量中?

每个实体都有不同的纹理,因此每个精灵都有不同的文件名。为了解决上述问题,我创建了自己的CCSprite子类,并在类中添加了几个NSString,用于存储值。这就像一个champ,但我仍然不确定为什么它不能使用CCSprite拥有的用户数据。