Search code examples
ioscocos2d-iphonensmutablearray

copy CCSprites between NSMutableArrays


i am copying a sprite from one NSMutableArray to another, but when i delete the CCSprite from the first NSMutableArray then it is also deleted in the second Array. How can i prevent this?

In the init method the Arrays are initialized like below.

  spriteTempArray =       [[NSMutableArray alloc] init] ; 
  myPowerUpArray =        [[NSMutableArray alloc] init] ;

This is the first method were the sprite is placed on screen and animated somewhere on the screen

 CCSprite *powerUpSprite = [[CCSprite alloc] initWithFile:SpriteFileName ]  ;
 powerUpSprite.position = ccp(xcenter,ycenter);
 powerUpSprite.scale = 0;
 [self addChild:powerUpSprite z:20 tag:puTag];
 [spriteTempArray addObject:powerUpSprite];
 id zoomIn = [CCScaleTo actionWithDuration:0.2 scale:1] ;
 id moveTo = [CCMoveTo actionWithDuration:0.2 position:ccp(winSize.width/2,120)];
 [powerUpSprite runAction:zoomIn];
 [powerUpSprite runAction:moveTo];

Then when de Sprite is touched, it's moved to the corner of the screen and also stored in another NSMutableArray (myPowerUpArray). But the delete action erases the sprite in both arrays.

  CCSprite *powerUpSprite = [spriteTempArray objectAtIndex:0];
  id zoomOut = [CCScaleTo actionWithDuration:0.2 scale:0.35] ;
  id moveTo  = [CCMoveTo actionWithDuration:0.2 position:ccp(winSize.width - 24,winSize.height -31 * myPowerUps -80)];  
  [powerUpSprite runAction:zoomOut];
  [powerUpSprite runAction:moveTo] 
  [myPowerUpArray addObject:powerUpSprite];
  [self deleteSpriteTempArray];

Below the sprite delete method.

 -(void)deleteSpriteTempArray{
     NSMutableArray *filesToRemove = [[NSMutableArray alloc] init];
     for ( id obj in spriteTempArray) {
         [filesToRemove addObject:obj];
         [self removeChild:obj  cleanup:YES];
     }
     [spriteTempArray removeObjectsInArray:filesToRemove];

}

I haven't observed the Array, other than de sprite is disappearing from the screen.


Solution

  • Your delete array method is odd. To begin why are you calling:

    [self removeChild:obj cleanup:YES];
    

    If your intent is not to remove the sprite from the scene? You are telling your code here to remove the sprite from the scene and to clean it up, but based on your post I don't get the impression you actually want that to happen at that moment. If it is your intent that it gets removed after it moves to the corner of your screen, then you should do the move and scale in a CCSpawn (let's simply call it moveScale) and in a CCSequence you should be adding that moveScale action followed by a block action that calls a method on the sprite to remove itself from its parent with cleanup:

    CGSize winSize = [[CCDirector sharedDirector] winSize];
    CCSprite* powerUp = ...;
    
    float duration = 0.2f;
    float desiredScale = 1.0f;
    CGPoint desiredPosition = ccp(winSize.width / 2,120);
    
    id zoomIn = [CCScaleTo actionWithDuration:duration scale:desiredScale] ;
    id moveTo = [CCMoveTo actionWithDuration:duration position:desiredPosition];
    
    id remove = [CCCallBlock actionWithBlock:^
    {
        [powerUp removeFromParentAndCleanup:YES];
    }];
    
    id moveScale = [CCSpawn actions:zoomIn, moveTo, nil];
    id moveScaleRemove = [CCSequence actions:moveScale, remove, nil];
    
    [powerUp runAction:moveScaleRemove];
    

    Secondly why do you have a "files to remove" array in your deletion method that is built with objects to remove? That "files to remove" array is adding all objects from the sprite temp array to it, so it seems a little pointless. Just remove all objects from your sprite temp array. No need to build another temp list with everything to remove, just to essentially be saying remove everything from my original temp array list. That would only be useful if you were removing only SOME of the objects in the temp array. Since you are removing all, the "files to remove" array doesn't serve a purpose. Or at least that is what your code is showing that you are doing. Whether you intend on that behavior is another question.

    Also if you have two arrays and an object in both, removing it from one array wouldn't have an impact on the second.

    Another issue with your code is in the first code block. If you intend on running a move and a scale action together, they need to be executed via a CCSpawn. Instead you are telling it to scale, then immediately telling it to move which therefore it will be moving but not scaling as it moves. In other words both are not occurring at the same time. On the other hand if you intend for them to be done in sequence, you should be executing them via a CCSequence.

    Another thing I noticed about your code is why are you deleting the entire sprite temp array when only one sprite was touched? Did you intend to only remove that one sprite that was touched? Why not just remove that one object, unless I am missing something?

    [spriteTempArray removeObject:thisPowerUpIJustTouched];
    

    A final issue I see is with your naming. Your code example indicates that the order of each example code block is the order in which events are occurring right? So why is the initial array you add powerups to called spriteTempArray while the array you add objects to after it is touched is called powerUpArray? Based on the code you've provided and the order they are shown, there is no point to the spriteTempArray. And even if there was, the naming looks backwards. Unless of course I'm missing something. It looks like your intention is to have a power ups array and when a power up is touched it is added to another array to mark that it is to be deleted. But as I've shown earlier in this post, it doesn't look like that second array has a true purpose since your desired behavior is A) not being done and B) would be done using the CCSpawn/CCSequence combo I showed earlier.

    Hope this helped. I just woke up so hopefully I addressed your issue properly.