Проблема сброса уровня Box2D и Cocos2d
У меня очень простой уровень, в котором есть одно статическое тело (и связанный спрайт). Когда пользователь касается тела, я удаляю спрайт, уничтожаю тело и заменяю его динамическим телом с новым спрайтом, а затем перехожу на новую сцену. Мой код работает отлично при первом запуске, но затем, когда эта сцена перезагружается, он падает, когда пользователь касается тела.
Я сохраняю имя файла.png, который я использую для своего спрайта, в поле userData спрайта. Затем, когда пользователь нажимает кнопку (касается тела), ее легко найти. Проблема возникает при последующих перезагрузках сцены, когда я пытаюсь получить доступ к полю 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];
}
}
}
1 ответ
Скорее всего, что NSString
освобождается при удалении спрайта. Почему бы просто не сохранить имя текстуры в переменной экземпляра?