reorderChild causing targetedTouch errors

Forums Programming cocos2d support (graphics engine) reorderChild causing targetedTouch errors

This topic contains 1 reply, has 2 voices, and was last updated by  rselig 2 years, 9 months ago.

Viewing 2 posts - 1 through 2 (of 2 total)
Author Posts
Author Posts
September 29, 2010 at 7:17 pm #225088

codeman9
Participant
@codeman9

I have my touch handling code in my CCSprite subclass. As part of my game, I store sprites in different arrays (to represent different players) and one of the actions a player can take requires me to remove a sprite from one array and add it to the other player’s array. I have a generic addSprite: and removeSprite: methods that seem to work fine independently, but in each method (addSprite: and removeSprite:) I call reorderChild: on my batch node to place the sprites at the correct zOrder. So what happens is that when I call, removeSprite: and addSprite: in quick succession (to remove from one array and add to another), the same sprite is being flagged for removal and addition as a targeted touch handler. This causes the exception: ‘Delegate already added to touch dispatcher.’ to trigger and crashes the app.

This is happening because reorderChild: in CCSpriteBatchNode simply calls removeChild: (which flags for removal from the touch dispatcher) and then addChild: (which flags for addition to the touch dispatcher). Calling reorder twice in quick succession on the same object queues up the touch dispatcher to add the same object twice and the exception is raised. Does anyone have any ideas on how I can redesign my code to fix this? Would a different implementation of reorderChild: in CCSpriteBatchNode work better? (one that actually reorders the array rather than adding and removing the child). This comment is from the CCSpriteBatchNode source file in reorderChild: “// XXX: Instead of removing/adding, it is more efficient to reorder manually”

Here is some code:

- (void)addSprite:(SQSprite *)aSprite atIndex:(NSUInteger)anIndex {
// Set the selected state of the sprite to unselected
if (aSprite.selectedState == kSpriteSelectedState) {
aSprite.selectedState = kSpriteUnselectedState;
}

// Insert the sprite into the sprites array
[self.sprites insertObject:aSprite atIndex:anIndex];

// Ensure that the sprites are placed above the background objects and the various other objects which are at z:0
[[[SQGame sharedGame] batchNode] reorderChild:aSprite z:self.player.playerPosition+10];
}

- (void)removeSprite:(SQSprite *)aSprite {
// Set the selected state of the sprite to unselected
if (aSprite.selectedState == kSpriteSelectedState) {
// Set the selected state of the sprite
aSprite.selectedState = kSpriteUnselectedState;
}

// Remove the identical sprite object from the sprites array
[self.sprites removeObjectIdenticalTo:aSprite];

// Ensure that the sprites are placed above the background objects and the various other sprites which are at z:0
[[[SQGame sharedGame] batchNode] reorderChild:aSprite z:1];
}

- (void)moveSprite:(SQSprite *)aSprite fromPlayer:(SQPlayer *)player1 toPlayer:(SQPlayer *)player2 {
// Remove the sprite from player1's hand model
[player1.container removeSprite:aSprite];
// Add the sprite to the player's hand in the model
[player2.container addSprite:aSprite atIndex:[player2.container.sprites count]];
}

Thanks.

July 4, 2011 at 1:04 pm #299382

rselig
@rselig

I read through CCNode source code and found that the touch delegate is not purged right away because I was calling reorderChild from within my CCTouchEnded method, and CCTouchDispatcher blocks removal of the delegate while a Touch is active. I worked around this by using a [self performSelector:@selector(performReorder:) withObject:nil afterDelay:.1];. In this way the touch ends, CCTouchDispatcher stops blocking the release of the delegate and after a small delay the node reorder occurs.

Viewing 2 posts - 1 through 2 (of 2 total)

You must be logged in to reply to this topic.