Cocos2d-iphone v3 touch event detection on CCNode with children

cocos2d-iphone, ios, iphone

Solution

You could override `hitTestWithWorldPos:` of your 'containing' node, either calling `hitTestWithWorldPos` on specific children or, iterating through all children as you see fit. Perhaps something like this:

-(BOOL) hitTestWithWorldPos:(CGPoint)pos
{
    BOOL hit = NO;    
    hit = [super hitTestWithWorldPos:pos];
    for(CCNode *child in self.children)
    {
        hit |= [child hitTestWithWorldPos:pos];
    }

    return hit;
}

edit: just to be clear, then you would only need to `setUserInteractionEnabled` for the container, and only process the touch using the touch events of the containing node.

edit2: so, I thought about it for a bit more and here's a quick category you can add that will enable a quick hit test for all children of a node recursively.

CCNode+CCNode_RecursiveTouch.h

#import "CCNode.h"
@interface CCNode (CCNode_RecursiveTouch)
{
}
-(BOOL) hitTestWithWorldPos:(CGPoint)worldPos forNodeTree:(id)parentNode shouldIncludeParentNode:(BOOL)includeParent;

@end

CCNode+CCNode_RecursiveTouch.m

#import "CCNode+CCNode_RecursiveTouch.h"

@implementation CCNode (CCNode_RecursiveTouch)

-(BOOL) hitTestWithWorldPos:(CGPoint)worldPos forNodeTree:(id)parentNode shouldIncludeParentNode:(BOOL)includeParent
{
    BOOL hit = NO;
    if(includeParent) {hit |= [parentNode hitTestWithWorldPos:worldPos];}

    for( CCNode *cnode in [parentNode children] )
    {
        hit |= [cnode hitTestWithWorldPos:worldPos];
        (cnode.children.count)?(hit |= [self hitTestWithWorldPos:worldPos forNodeTree:cnode shouldIncludeParentNode:NO]):NO; // on recurse, don't process parent again
    }
    return  hit;
}

@end

usage would just be .. in the containing class, override hitTestWithWorldPos like this:

-(BOOL) hitTestWithWorldPos:(CGPoint)pos
{
    BOOL hit = NO;
    hit = [self hitTestWithWorldPos:pos forNodeTree:self shouldIncludeParentNode:NO];
    return hit;
}

and of course, don't forget to include the category header.

Problem

I have a `CCNode` that contains multiple `CCSprite` children. I would like to receive touch events in my parent `CCNode` if any of the children have been touched. This behaviour seems like it should be supported, I may be missing something. My solution is to `setUserInteractionEnabled = YES` on all children and bubble the event up to the parent. I do this by subclassing the `CCSprite` class overriding their method : ``` - (void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { [super touchBegan:touch withEvent:event]; } ``` I am wondering if there is a more elegant, simple and generic way of accomplishing the same behaviour ?

Original source