Tibor Udvari
Tibor Udvari

Reputation: 3012

Cocos2d-iphone v3 touch event detection on CCNode with children

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.

cake

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 ?

Upvotes: 2

Views: 2594

Answers (2)

shay.h
shay.h

Reputation: 21

-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event

{

    //Do whatever you like...

    //Bubble the event up to the next responder...
    [[[CCDirector sharedDirector] responderManager] discardCurrentEvent];


}

Upvotes: 1

Mark
Mark

Reputation: 876

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.

Upvotes: 7

Related Questions