如何从SKSpriteNode或SKTexture中获取像素颜色?

3

我希望能够精确选择游戏地图上的对象。对象是一个精灵,周围有一些透明像素,我想测试这些透明像素的触摸位置。有什么线索吗?

3个回答

3

在Sprite Kit中,您无法访问纹理数据。

相反,您需要从图像创建位掩码,例如通过将图像加载为UIImage或CGImage并扫描所有非透明像素。


1
哪个类更适合此目的?这两个类中哪一个在以像素级别处理图像方面具有更好的功能(和性能)? - prototypical

2

以下是直接从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)
    }
}

这在Swift 3中是什么样子的?我无法切换它。 - bluelemonade

2
你可以继承 SKSpriteNode 类,添加一个对图像的引用,并在检测触摸时检查该图像的 alpha 值。

1)添加一个实例变量来保存你的图像。

@implementation DraggableSprite {
    UIImage *_holdingImage;
}

2) 然后在init方法中,您可以保存对该图像的引用

-(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) 检测触摸

-(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) alpha检查功能

+(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: https://dev59.com/w3NA5IYBdhLWcg3wPLL-
    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;
}

我在“let scene = ...”后面立即加上了以下两行代码:view.allowsTransparency = true; scene.backgroundColor = UIColor(red:0, green:0, blue:0, alpha:0)。否则,你会得到标准的背景Alpha +颜色。 - Christian J. B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接