James
James

Reputation: 746

Error removing sprites from a spritesheet in Cocos2D

I'm in the initial building stages of an iphone game, and I'm using sprite sheets to create some random people, each one with sub-sprites for hair, clothing etc.

I'm storing my sprite images in spritesheets using CCSpriteBatchNode. I'm just doing an initial setup test now, where you tap the screen to generate a new random set of people. So the weird thing is, you can tap once and it will remove the old people and replace them with new people, but the second time, it crashes with the error: "CCSpriteBatchNode doesn't contain the sprite. Can't remove it" Now I'm sure I've added the sprite to the batch node, in my Person.m constructor I have this line:

        [spriteSheet addChild:person];

In my test code in ccTouchesEnded I've got the following code:

//updated with changes suggested by Mazyod and Jer
for(int i=6; i>=0; i--){
    Person *per = [_people objectAtIndex:i];
    [_people fastRemoveObjectAtIndex:i];
    [_spritesheet removeChild:per cleanup:YES];
    per = nil;
}


for(int i = 0; i < 7; i++){
    Person *per = nil;
    per = [Citizen personFromCountry:_country1 WithSpriteSheet:_spritesheet];
    per.position = ccp(100 + (50 * i),160);
    [_people addObject:per];
    [_spritesheet addChild:per];
}

Can anybody suggest what I'm missing? I've read a bunch about spritesheets in cocos2d and am given to understand that removing individual sprites is tricky so I'm sure there's some vital lines I need to add here. Thanks for your help!

Edit: I googled the error and found this thread: http://www.cocos2d-iphone.org/forum/topic/17170 which seems to confirm that Cocos2d thinks I'm not adding the sprite to the spritesheet - but I am, as proven by the fact that the sprites add correctly the first time, just not the second.

One solution is to simply avoid removing the sprites at all, just make them invisible and redraw them with new characteristics when they need to be reused. I'd rather know what the real solution is though because it seems cleaner.

Upvotes: 0

Views: 624

Answers (3)

Mark
Mark

Reputation: 61

I just want to mention my experience here with this problem and how I solved it.

Remember, you are either trying to remove a child that was never added..

OR

Trying to remove a child TWICE.

This was the case for me. The collision detection in my game was solid (at least I thought). Then randomly, like 1 out of every 7-10 runs... I would get this crash. I realized it was because I had coded my projectiles to be removed once they intersected a target.

I did not however, put a failsafe where IF my tick method detected that it was in collision with MORE then 1 target at a time.

This was because for every projectile, I iterated through each target to check for a collision, then removed the respective projective if collision was detected. So I created a simple BOOL, and set it to YES if it had already collided with a target. Then I only checked for collision if the projectile had not collided with anything.

So... before:

if (CGRectIntersectsRect(projectileRect, targetRect))
{
//code to remove projectile
}

After:

if (CGRectIntersectsRect(projectileRect, targetRect) && projectile.hasHitaTarget == NO)
{
//code to remove projectile
}

Upvotes: 1

Jer In Chicago
Jer In Chicago

Reputation: 828

Looks like you need to change

[_people addObject:per];

to

[_people replaceObjectAtIndex:i withObject:per];

In your first loop you are just setting the value of the object in the array to nil, but not removing it from the array. In the second loop you just add it onto the end of the array, but your array already has 7 nils in it.

Let me know if it works.

Upvotes: 1

Mazyod
Mazyod

Reputation: 22559

Well, I could help you clear out one thing for now:

Any CCNode can only be a child to one parent. ie It has to have a single parent.

But, what you have here:

for(int i=0; i<7; i++){
    Person *per = [_people objectAtIndex:i];
    [self removeChild:per cleanup:YES];
    [_spritesheet removeChild:per cleanup:YES];
    per = nil;
}

Suggest you are trying to add the person to both the spriteSheet and self at the same time.. Check your Log, it must have something like:

cocos2d: removeChild, child not found.

And from the error you are getting, I am betting that the person is added to self and not to the sprite sheet.

So, how to solve this?

Well, you have to add the person to the spriteSheet as a child, then add the spriteSheet to self as a child. (Actually, the order you add them doesn't matter).

Sort this out, and maybe this problem will go away, or at least it will be clearer so we can help you.

Upvotes: 1

Related Questions