1

Before I ask this question, I have double checked the following questions and examples:

  1. SKCropNode not working on device while working on simulator

  2. Swift 3: cut a hole in a SKSpriteNode

The above works well on all simulators, however, it doesn't work on real device.

My Code in ObjetiveC:

SKSpriteNode* mask = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:size];
mask.position = CGPointMake(size.width/2, size.height/2);
mask.name = @"Mask";
mask.alpha = 0.5;
mask.zPosition = 3;

SKSpriteNode* node = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:size];
node.position = CGPointMake(size.width/2, size.height/2);
node.name = @"circleMask";
node.zPosition = 1;
node.alpha = 1;
SKShapeNode* circleNode = [SKShapeNode shapeNodeWithCircleOfRadius:100/2+20];
circleNode.fillColor = [UIColor whiteColor];
circleNode.lineWidth = 0;
circleNode.alpha = 1;
circleNode.position = CGPointMake(80, -200);
circleNode.name = @"circleNode";
circleNode.zPosition = 1;
circleNode.blendMode = SKBlendModeSubtract;
[node addChild:circleNode];

SKCropNode* cropNode = [[SKCropNode alloc] init];
cropNode.name = @"cropNode";
cropNode.position = CGPointZero;
cropNode.zPosition = 2;
[cropNode setMaskNode: node];
[cropNode addChild:mask];
[scene addChild:cropNode];

I am wondering if someone has successfully implemented the feature with similar approach above, if yes, please clarify it a little bit, if not, can you post your solution? thanks a lot.

I attached a Picture to show the same code running on Simulator and a iPhone 6: Picture to show the issue

My plan:

Instead of using SKCropNode, I will programmatically create a UIImage with a hole at the right position and render it as a texture of a SKSpriteNode. I have implemented the feature by init a SKSpriteNode with the created UIImage:

-(instancetype)init{
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGRect spotLightRect = CGRectMake(100,100,200,200); // adjust this as desired!
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
    CGContextRef c = UIGraphicsGetCurrentContext();
    UIColor*bColor = [UIColor colorWithRed:0 green:0.0 blue:0 alpha:0.5];
    CGContextSetFillColorWithColor(c, bColor.CGColor);
    CGContextFillRect(c, rect); //the mask
    UIColor*aColor = [UIColor colorWithRed:0 green:0.0 blue:0 alpha:1];
    CGContextSetFillColorWithColor(c, aColor.CGColor);
    CGContextSetBlendMode(c, kCGBlendModeClear);
    CGContextFillEllipseInRect(c, spotLightRect); //the hole
    UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    SKTexture* texture = [SKTexture textureWithImage:image];
    self = [super initWithTexture:texture];
    return self;
}
sam huang
  • 11
  • 4

1 Answers1

1

You are having problems with your position and math, I am going to break it down

Leave:

SKSpriteNode* mask = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:size];

remove:

mask.position = CGPointMake(size.width/2, size.height/2);

leave:

mask.name = @"Mask";
mask.alpha = 0.5;

remove:

mask.zPosition = 3;

leave:

SKSpriteNode* node = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:size];

remove:

node.position = CGPointMake(size.width/2, size.height/2);

leave:

node.name = @"circleMask";

remove:

node.zPosition = 1;

leave:

node.alpha = 1;
SKShapeNode* circleNode = [SKShapeNode shapeNodeWithCircleOfRadius:100/2 + 20];
circleNode.fillColor = [UIColor whiteColor];
circleNode.lineWidth = 0;
circleNode.alpha = 1;
circleNode.position = CGPointMake(80, -200);
circleNode.name = @"circleNode";

remove:

circleNode.zPosition = 1;

leave:

circleNode.blendMode = SKBlendModeSubtract;
[node addChild:circleNode];

SKCropNode* cropNode = [[SKCropNode alloc] init];
cropNode.name = @"cropNode";
cropNode.position = CGPointZero;
cropNode.zPosition = 2;
[cropNode setMaskNode: node];
[cropNode addChild:mask];
[scene addChild:cropNode];

Final result:

SKSpriteNode* mask = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:size];
mask.name = @"Mask";
mask.alpha = 0.5;

SKSpriteNode* node = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:size];
node.name = @"circleMask";
node.alpha = 1;
SKShapeNode* circleNode = [SKShapeNode shapeNodeWithCircleOfRadius:100/2+20];
circleNode.fillColor = [UIColor whiteColor];
circleNode.lineWidth = 0;
circleNode.alpha = 1;
circleNode.position = CGPointMake(80, -200);
circleNode.name = @"circleNode";
circleNode.blendMode = SKBlendModeSubtract;
[node addChild:circleNode];

SKCropNode* cropNode = [[SKCropNode alloc] init];
cropNode.name = @"cropNode";
cropNode.position = CGPointZero;
cropNode.zPosition = 2;
[cropNode setMaskNode: node];
[cropNode addChild:mask];
[scene addChild:cropNode];

You should now have a black screen with a hole at 80,-200

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • @KnightOfDragon thank you very much for your prompt reply. I tried your final sample code, unfortunately, it can't not make a hole on real device, I tested on iPhone 6, iPhone 5s, iPhone 7 with IOS 10, 11. But it do work on all Simulators. Do you have any other idea? – sam huang Dec 02 '17 at 06:07
  • what method are you doing this in? – Knight0fDragon Dec 02 '17 at 06:09
  • I just created a very simple SK project with only your code in. only have a SKView, a SKScene, and a SKSpriteNode. but it doesn't work. – sam huang Dec 02 '17 at 06:18
  • I am not very sure what is your question for, I just put it in viewDidLoad in my ViewController where I initialized a SKView , a SKScene and a SKSpriteNode. – sam huang Dec 02 '17 at 07:56