In SpriteKit, SKCropNode does not affect SKShapeNode

I am trying to apply a mask to SKShapeNode using SKCropNode and still without success. Thinking this is a SpriteKit error - here is a piece of code:

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? Many thanks!

+8
objective-c sprite-kit
source share
3 answers

It bothered me most of the day. I planned to create a timer similar to the excellent TCProgressTimer from Tony Chamblee . However, since my application uses several progress timers, I did not want to create dozens of different sprites of different sizes for use with different resolutions.

My solution was to convert SKShapeNode objects to SKSpriteNode objects. I had to go back to the basics and use Core Graphics for hard work. This is a pretty dirty way to do something, I'm sure, but I wanted fast results to dynamically create objects that resembled the results obtained using SKShapeNode .

I'm only interested in creating circle objects, 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 using SKCropNode , as expected. Since these sprites are generated before the start of the scene, I do not notice a performance hit. However, I would suggest that this method is very inefficient if you create multiple nodes on the fly.

I would really like to hear decisions from other users. Hope this helps.

-DC

+8
source share

I have a similar task in my application. I need to draw some irregular shapes based on user input and then use them as node masks.

The solution that works for me is:

  • create SKShapeNode with the desired path

  • extracts SKTexture from it using the SKView method textureFromNode:crop:

  • create SKSpriteNode from this texture.

  • use SKSprite node as a mask.

+4
source share

Your name is correct. I also found that the ShapeNode in the CropNode hierarchy also affects the children above it. I created a quick experiment. You can create a new game project and try it yourself. Commenting on one of the addChild: shapeContent lines, you can see how it affects cropping of the spacecraft image.

As DoctorClod points out, the current solution seems to guarantee that all cropNode child objects are SpriteNodes.

 -(void)didMoveToView:(SKView *)view { SKSpriteNode* colorBackground = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(800, 600)]; SKSpriteNode *spaceshipImage = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"]; SKShapeNode* shapeContent = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 200, 100)]; shapeContent.fillColor = [SKColor greenColor]; SKSpriteNode *maskShape = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(500, 100)]; SKCropNode *cropNode = [SKCropNode new]; [cropNode addChild:colorBackground]; [cropNode addChild:shapeContent]; // comment this one out [cropNode addChild:spaceshipImage]; [cropNode addChild:shapeContent]; // or comment this one out [cropNode setMaskNode:maskShape]; cropNode.position = CGPointMake(CGRectGetMidX (self.frame), CGRectGetMidY(self.frame)); [self addChild:cropNode]; } 
+2
source share

All Articles