Search code examples
iosobjective-csprite-kitsknode

Objective C - SKNode subclass to 'swallow' touches?


I am trying to subclass an SKNode so that when you touch its frame (the minimum frame to enclose its children), it is notified by the touchesBegan:: method.

However, it seems that it will only be notified if a SKSpriteNode child is touched. I have tried overriding the containsPoint: method but with no success.

Here is my code:

@interface gameNode : SKNode {
    SKSpriteNode* mainChar;
}

@property (weak, nonatomic) id <gameNodeDelegate> delegate;

@end

@implementation gameNode // When touched, touchesBegan: method not getting called.

-(id) init {
    if (self = [super init]) {

        self.userInteractionEnabled = YES;

        mainChar = [SKSpriteNode node]; // When touched, touchesBegan: method gets called.
        mainChar.color = [SKColor redColor];
        mainChar.size = CGSizeMake(25, 25);
        [mainChar runAction:[SKAction scaleTo:0 duration:0]];
        mainChar.position = CGPointMake(100, 100);
        [self addChild:mainChar];

        SKSpriteNode* n = [SKSpriteNode node]; // When touched, touchesBegan: method gets called.
        n.size = mainChar.size;
        n.position = CGPointMake(-100, -100);
        n.color = [SKColor greenColor];
        [self addChild:n];

        [mainChar runAction:[SKAction customAnimationWithProperties:CUAPropertiesForScaleBounce(CUADirectionTypeIn, 1)]];

    }
    return self;
}

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"That's a touch!");
}

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

}

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

}

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

}

@end

What happens is I only get a touch event when the mainChar and n SKSpriteNodes nodes are touched and not the rest of the screen.

The only way I could think to get it to work is to add a transparent SKSpriteNode to the background, but there must be a better way!

How can I make it so the SKNode 'swallows' the touches it receives, regardless of whether a child is being child is being touched? i.e I want touches in the SKNodes's frame to notifiy it via the touchesBegan:: method.

Update: I think this is a problem with the SKNode's frame. When I do after adding the children..

NSLog(@"Frame Width: %f, Frame Height: %f", self.frame.size.width, self.frame.size.height);

The frame is returned as having a height and width of 0. However, when I do [self calculateAccumulatedFrame], it returns the correct size. Why is this?

Update: This question is a complete mess. I am just going to stick with the solution of adding a transparent SKSpriteNode or using an SKScene. Sorry for the bafflement everyone, I appreciate your help.


Solution

  • An SKNode doesn't have any intrinsic bounds. It does not perform any drawing, and you can effectively think of it not being rendered on the screen either. It will not detect touches.

    The functionality you are looking for is best provided by an SKScene. Use an SKScene.