0

我有一个非常简单的关卡,其中有一个静态主体(和关联的精灵)。当用户触摸身体时,我移除精灵,销毁身体并用带有新精灵的动态身体替换它,然后我过渡到新场景。我的代码在第一次执行时运行良好,但是当重新加载这个场景时,当用户触摸身体时它会崩溃。

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

我不明白为什么它是第一次而不是第二次。我设置了一个断点并观察分配给精灵的 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];
    }
}

}

4

1 回答 1

0

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

于 2013-04-13T17:23:09.533 回答