Reputation:
Basically I want to achieve something like this : https://github.com/moqod/iOS-Scratch-n-See in SpriteKit.
In a SKScene ,I have a car image,2-3 different types of layers of dirt images, one layer of soap , one layer of water droplets and by these layers i mean all of them are in UIImage form and equal to car frame's size(which i can use as SKTexture and SKNode eventually). The project mentioned above adds UIImageView on one another and than erase images. I need to manage many layers like if a soap tool is selected ,I want to bring up the dirt image layer , erase the dirt image wherever user touches and below it i will place soap image(semi-transparent) ,which will be visible now and below it car image. After merging them(half erased/half present dirt+soap+car image) i will get another image and display it on top ,so this will give an impression to the user as if he is applying soap on car and removing dirt. If you can see what i am trying to explain.
I want to use above mentioned project and achieve these tasks on SpriteKit.
I cant use z-position to bring upfront and move back the images as it works only on SKSpriteNode and above example is coded on UIKit (UIImages) to erase images and not nodes.
I cant add transparent SKScenes on one another ,ex : Making a SKScene's background transparent not working... is this a bug? , same way as UIImageView's are added on that project as i am working on IOS 7 and want my application to be compatible with it. Last resort would be i need to drop SpriteKit and work on UIKit.
Any logic to swipe over a SKSpriteNode and make its particluar swiped area transparent by changing its alpha value or something ?
Any help or suggestions are most welcomed. Thank You.
Upvotes: 2
Views: 610
Reputation: 12773
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
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];
}
}
}
}
Upvotes: 2