w3hello.com logo
Home PHP C# C++ Android Java Javascript Python IOS SQL HTML videos Categories
Scratch a SKNode and reveal SKNode underneath it , an effect like wiping a misted glass

You can implement a "scratch and see" using Sprite Kit's SKCropNode. An SKCropNode applies a mask to its children nodes. The mask is used to hide part or all of the crop node's children. For this app, the child node is the image you would like to uncover by "scratching."

The basic steps

  1. Start with an empty image as the texture for the mask
  2. Add circles to the mask where the user touches the hidden image to uncover the picture below

Here's an example of how to do that:

First, define these properties

@property UIImage *image;
@property SKSpriteNode *maskNode;
@property SKNode *node;

then add the contents of the scene to didMoveToView.

-(void)didMoveToView:(SKView *)view {

    self.node = [SKNode node];
    _node.name = @"tree";

    // Create a node that will hold the image that's hidden and later
uncovered by "scratching"
    CGPoint position = CGPointMake
(CGRectGetWidth(self.frame)/2,CGRectGetHeight(self.frame)/2);
    SKSpriteNode *imageNode = [SKSpriteNode
spriteNodeWithImageNamed:@"hidden_pic.png"];
    imageNode.position = CGPointZero;

    CGSize size = imageNode.size;

    // This is the layer that you "scatch" off
    SKSpriteNode *background = [SKSpriteNode spriteNodeWithColor:[SKColor
grayColor] size:size];
    background.position = position;
    background.name = @"background";
    [_node addChild:background];

    // This is the mask node. Initialize it with an empty image, so it
completely hides the image
    UIImage *image = [self blankImageWithSize:size];
    self.image = image;
    SKTexture *texture = [SKTexture textureWithImage:image];
    SKSpriteNode *maskNode = [SKSpriteNode spriteNodeWithTexture:texture];
    maskNode.position = CGPointZero;
    maskNode.name = @"mask";
    self.maskNode = maskNode;

    [_node addChild:maskNode];

    // This is the node that crops its children
    SKCropNode *cropNode = [SKCropNode node];
    cropNode.position = position;
    cropNode.maskNode = maskNode;
    cropNode.zPosition = 100;
    cropNode.name = @"crop";

    [_node addChild:cropNode];


    [cropNode addChild:imageNode];

    [self addChild:_node];
}

This creates an empty image. It is used to as the initial mask image so that the picture is completely hidden.

- (UIImage*) blankImageWithSize:(CGSize)size
{
    UIGraphicsBeginImageContext(size);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

This method draws a circle on an image at a specified point. It is used to update the mask node's image. Each circle drawn on the mask uncovers more of the hidden picture.

#define kCircleRadius   22

- (UIImage *)imageByDrawingCircleOnImage:(UIImage *)image
atPoint:(CGPoint)point
{
    UIGraphicsBeginImageContext(image.size);

    [image drawAtPoint:CGPointZero];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -image.size.height);

    CGRect rect = CGRectMake(point.x-kCircleRadius, point.y-kCircleRadius,
                             kCircleRadius*2, kCircleRadius*2);
    UIBezierPath* roundedRectanglePath = [UIBezierPath
bezierPathWithOvalInRect:rect];
    [[UIColor blackColor] setFill];
    [roundedRectanglePath fill];

    CGContextAddPath(context, roundedRectanglePath.CGPath);

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

    return newImage;
}

This method converts the specified point to the mask node's coordinates, calls a method to draw a circle in the mask node, and updates the mask node's texture.

- (void) drawCircleInImageAtPoint:(CGPoint)point
{
    CGPoint location = [self convertPoint:point toNode:_maskNode];
    location = CGPointMake(location.x+_maskNode.size.width/2,
location.y+_maskNode.size.height/2);
    UIImage *newImage = [self imageByDrawingCircleOnImage:_image
atPoint:location];
    SKTexture *texture = [SKTexture textureWithImage:newImage];
    self.image = newImage;
    _maskNode.texture = texture;
}

These methods handle touch events. It adds cicles to the mask node image where the user touched the screen.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    /* Called when a touch begins */

    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        NSArray *nodes = [self nodesAtPoint:location];
        for (SKNode *node in nodes) {
            if ([node.name isEqualToString:@"crop"]) {
                [self drawCircleInImageAtPoint:location];
            }
        }
    }
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        NSArray *nodes = [self nodesAtPoint:location];
        for (SKNode *node in nodes) {
            if ([node.name isEqualToString:@"crop"]) {
                [self drawCircleInImageAtPoint:location];
            }
        }
    }
}




© Copyright 2018 w3hello.com Publishing Limited. All rights reserved.