0

I am using CCNode userData property to define whether a touched sprite has had a node built upon it (using Ray Wenderlich's - Tower Defence Tutorial).

The problem I am having is that for every new sprite position I touch and build upon, the previous ones are not retained in the sense that I am unable to sell the building built on it using my sell method.

What is the best way to save data to an individual CCSprite that is selected by touch, and defined by a property through a for loop?

I have read that subclassing CCSprite is an option, or creating a struct for userData etc. I have tried to implement these strategies but have been unsuccessful getting them to work.

touch method with sprite property:

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    for(UITouch *touch in touches){
    CGPoint location = [touch locationInView:[touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];

    for(CCSprite *tb in self.BuildPositions){
//BuildPositions contains CCSprites from a class defining build positions and contained in a mutable array.
        if(CGRectContainsPoint([tb textureRect],[tb convertToNodeSpace:location ])){

            _selectedBuildPosition = tb;
            [self buildMenuTapped];
      }
    }
  }
}

build menu method:

-(void)buildMenuTapped{

[self removeChild:_buildSelectMenu cleanup:YES];
[self removeChild:_sellBuildingMenu cleanup:YES];

if (_selectedBuildPosition.userData == nil) {

    CCMenuItem *buildOption = [CCMenuItemImage itemWithNormalImage:@"building.png" selectedImage:@"building.png" target:self selector:   @selector(buildOption)];
    buildOption.position = ccpAdd(_selectedBuildPosition.position,ccp(0,40));

    _buildSelectMenu = [CCMenu menuWithItems:BuildOption, nil];
    _buildSelectMenu.position = CGPointZero;
    [self addChild:_buildSelectMenu z:100];

}else{

    [self sellBuildingMenu];
}
}

build upon method:

-(void)buildOption{

if([self canBuyBuilding] && !_selectedBuildPosition.userData){

    _playerEssence -= kBUILD_COST;

    _lvl1BuildNodeInstance = [lvl1BuildNode nodeWithTheGame:self location:_selectedBuildPosition.position];
//method as seen in RW tutorial. Generates a lvl1BuildNode class node within the HelloWorldLayer.

    _selectedBuildPosition.userData = (__bridge void*)(_lvl1BuildNodeInstance);

  }
}

sell menu method:

-(void)sellBuildingMenu{
[self removeChild:_buildSelectMenu cleanup:YES];
[self removeChild:_sellBuildingMenu cleanup:YES];

CCMenuItem *buildingSell = [CCMenuItemImage itemWithNormalImage:@"sell.png" selectedImage:@"sell.png" target:self selector:@selector(sellBuilding)];
buildingSell.position =  ccpAdd(_selectedBuildPosition.position,ccp(40,0));

_sellBuildingMenu = [CCMenu menuWithItems:buildingSell, nil];
_sellBuildingMenu.position = CGPointZero;
[self addChild:_sellBuildingMenu z:100];
}

sell method:

-(void)sellBuilding{
    if (_selectedBuildPosition.userData == (__bridge void*)(_lvl1BuildNodeInstance)){

        [self removeChild:_lvl1GemNodeInstance cleanup:YES];

        [_buildings removeObject:_lvl1BuildNodeInstance];

        _playerEssence += kBUILD_COST;

        _selectedBuildPosition.userData = nil;

    }else{
    }
}

Thank you for your time.

Eric
  • 27
  • 6
  • First of all, use userObject (id) instead of userData (void*) because then these objects will be properly memory managed by ARC and you don't need to bridge cast. Then consider that instead of assigning the node directly, you can have the userObject be a dictionary or wrapper class with storage to add multiple nodes to it. Finally, it's really really bad practice to store references to nodes other than the class they were created in / added to because this quickly leads to retain cycles, preventing objects from being deallocated. – CodeSmile Sep 17 '13 at 15:08
  • Thanks for the input Steffen. I'll give userObject a go. With regards to making userObjects into a dictionary, whats the best method to do so? I take it, that it will have to be mutable since we will be adding entries in after the CCSprite userObject is changed? – Eric Sep 18 '13 at 04:10
  • Yes, needs to be mutable. Just create a dictionary and assign it to userObject. – CodeSmile Sep 18 '13 at 08:44
  • Awesome, the method sort of works. I'm still having issues selling the correct selected building however, removeChild only works for the most recently created node. I'll have a play around with the if statement and method. Cheers Stefen. – Eric Sep 18 '13 at 23:19

0 Answers0