In SpriteKit, SKCropNode has no effect over a SKShapeNode

objective-c, sprite-kit

Solution

This had been bugging me for most of the day. I had planned to create a timer similar to the excellent TCProgressTimer by Tony Chamblee. However, as my application uses multiple progress timers I didn't want to have to design dozens of different sized sprites for use at different resolutions.

My solution was to convert `SKShapeNode` objects to `SKSpriteNode` objects. I ended up having to go back to basics and use Core Graphics to do the heavy lifting. This is a rather messy way of doing things, I'm sure, but I wanted quick results to dynamically create objects that would resemble the results obtained when using `SKShapeNode`.

I am only interested in making circle objects at present, so I did it like this:

-(SKSpriteNode *)createSpriteMatchingSKShapeNodeWithRadius:(float)radius color:(SKColor *)color {
    CALayer *drawingLayer = [CALayer layer];
    CALayer *circleLayer = [CALayer layer];
    circleLayer.frame = CGRectMake(0,0,radius*2.0f,radius*2.0f);
    circleLayer.backgroundColor = color.CGColor;
    circleLayer.cornerRadius = circleLayer.frame.size.width/2.0;
    circleLayer.masksToBounds = YES;


    [drawingLayer addSublayer:circleLayer];

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(circleLayer.frame.size.width, circleLayer.frame.size.height), NO, [UIScreen mainScreen].scale);
    CGContextSetAllowsAntialiasing(UIGraphicsGetCurrentContext(), TRUE);
    CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [UIColor clearColor].CGColor);
    CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0,0,circleLayer.frame.size.width,circleLayer.frame.size.height));
    [drawingLayer renderInContext: UIGraphicsGetCurrentContext()];

    UIImage *layerImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImage:layerImage]];


    return sprite;
}

The resulting sprite can now be masked by an `SKCropNode` as expected. As these sprites are all generated before the scene begins, I do not notice a performance hit. However, I would imagine this method is highly inefficient if you are generating multiple nodes on the fly.

I would be eager to hear solutions from other users. Hope that helps.

-DC

Problem

I've been trying to apply a mask to a SKShapeNode using SKCropNode, and so far without success. Thinking that it's a SpriteKit bug - Here is the code snippet: ``` SKNode* contentNode = [SKNode node]; // picture - use an image bigger than 50x50 SKSpriteNode *pictureNode = [SKSpriteNode spriteNodeWithImageNamed:@"tree"]; // triangle SKShapeNode* triangleNode = [SKShapeNode node]; UIBezierPath* triangleNodeBezierPath = [[UIBezierPath alloc] init]; [triangleNodeBezierPath moveToPoint:CGPointMake(0.0, 0.0)]; [triangleNodeBezierPath addLineToPoint:CGPointMake(0.0, 100.0)]; [triangleNodeBezierPath addLineToPoint:CGPointMake(50.0, 100.0)]; [triangleNodeBezierPath closePath]; triangleNode.path = triangleNodeBezierPath.CGPath; triangleNode.fillColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1]; // create a mask SKSpriteNode *mask = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size: CGSizeMake(50, 50)]; //50 by 50 is the size of the mask // create a SKCropNode SKCropNode *cropNode = [SKCropNode node]; [cropNode addChild: contentNode]; [cropNode setMaskNode: mask]; [self addChild: cropNode]; [contentNode addChild:pictureNode]; // pictureNode is being cropped [contentNode addChild:triangleNode]; // triangleNode is not cropNode.position = CGPointMake( CGRectGetMidX (self.frame), CGRectGetMidY (self.frame)); ``` Does anyone have a workaround about this issue? Thanks a lot!

Original source