I want to get precise selection of my object on game map. Object is a sprite with which has some transparent pixels around and I want to test touch location for these transparent pixels. Any clue?
Asked
Active
Viewed 3,484 times
3 Answers
3
In Sprite Kit you don't have access to texture data.
Instead you'd have to create a bit mask from the image, for example by loading the image as UIImage or CGImage and scanning for all non-transparent pixels.

CodeSmile
- 64,284
- 20
- 132
- 217
-
1Which is the better class to use for this purpose ? Which of the two classes has better capabilities (and performance) in working with images at the pixel level ? – prototypical Oct 17 '13 at 22:48
2
You can subclass SKSpriteNode, add a reference to the image and check the alpha of that image, when detecting touches.
1) Add an instance variable to hold your image
@implementation DraggableSprite {
UIImage *_holdingImage;
}
2) Then in init method you can save the reference to that image
-(id)initWithImageNamed:(NSString *)name {
if (self=[super initWithImageNamed:name]) {
self.userInteractionEnabled = YES;//enable touches handling
self.anchorPoint = P(0,0);
_holdingImage = [UIImage imageNamed:name];
}
return self;
}
3) Detect the touches
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
CGFloat a = [UIImage getAlphaFromImage:_holdingImage atX:positionInScene.x andY:self.size.height-positionInScene.y];
NSLog(@"alpha is %f",a);
}
4) The alpha checking function
+(CGFloat)getAlphaFromImage:(UIImage*)image atX:(NSInteger)xx andY:(NSInteger)yy {
// Cancel if point is outside image coordinates
if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), CGPointMake(xx,yy))) {
return 0;
}
// Create a 1x1 pixel byte array and bitmap context to draw the pixel into.
// Reference: http://stackoverflow.com/questions/1042830/retrieving-a-pixel-alpha-value-for-a-uiimage
NSInteger pointX = xx;
NSInteger pointY = yy;
CGImageRef cgImage = image.CGImage;
NSUInteger width = image.size.width;
NSUInteger height = image.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * 1;
NSUInteger bitsPerComponent = 8;
unsigned char pixelData[4] = { 0, 0, 0, 0 };
CGContextRef context = CGBitmapContextCreate(pixelData,
1,
1,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextSetBlendMode(context, kCGBlendModeCopy);
// Draw the pixel we are interested in onto the bitmap context
CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
CGContextRelease(context);
CGFloat alpha = (CGFloat)pixelData[3] / 255.0f;
return alpha;
}

roman777
- 486
- 6
- 9
-
I amended your code with the following two lines immediately following 'let scene = ...': view.allowsTransparency = true; scene.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0). Otherwise you get the standard background alpha + color. – Christian J. B. May 25 '15 at 20:26
2
Here is how to get the color of one pixel directly from the SKTexture:
class SpriteKitUtility
{
class func pixelFromTexture(texture: SKTexture, position: CGPoint) -> SKColor {
let view = SKView(frame: CGRectMake(0, 0, 1, 1))
let scene = SKScene(size: CGSize(width: 1, height: 1))
let sprite = SKSpriteNode(texture: texture)
sprite.anchorPoint = CGPointZero
sprite.position = CGPoint(x: -floor(position.x), y: -floor(position.y))
scene.anchorPoint = CGPointZero
scene.addChild(sprite)
view.presentScene(scene)
var pixel: [Byte] = [0, 0, 0, 0]
let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
let context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), bitmapInfo);
UIGraphicsPushContext(context);
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
UIGraphicsPopContext()
return SKColor(red: CGFloat(pixel[0]) / 255.0, green: CGFloat(pixel[1]) / 255.0, blue: CGFloat(pixel[2]) / 255.0, alpha: CGFloat(pixel[3]) / 255.0)
}
}

Martin
- 10,738
- 14
- 59
- 67