【问题标题】:How to get pixel color from SKSpriteNode or from SKTexture?如何从 SKSpriteNode 或 SKTexture 获取像素颜色?
【发布时间】:2013-10-17 21:56:45
【问题描述】:

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

【问题讨论】:

    标签: iphone objective-c sprite-kit


    【解决方案1】:

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

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

    【讨论】:

    • 为此目的使用哪个更好的类?这两个类中的哪一个在处理像素级别的图像方面具有更好的能力(和性能)?
    【解决方案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: 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;
    }
    

    【讨论】:

    • 我在'let scene = ...'之后使用以下两行修改了您的代码:view.allowsTransparency = true; scene.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)。否则你会得到标准的背景 alpha + 颜色。
    【解决方案3】:

    这里是如何直接从 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中看起来如何,我无法切换它。
    猜你喜欢
    • 1970-01-01
    • 2018-09-07
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    相关资源
    最近更新 更多