Cocoa 使用CALayer内容的alpha属性使用CALayer进行命中测试

Cocoa 使用CALayer内容的alpha属性使用CALayer进行命中测试,cocoa,calayer,Cocoa,Calayer,我正在为Mac编写一个使用Cocoa的游戏。我目前正在实施命中测试,发现CALayer提供命中测试,但似乎没有实现alpha属性。由于我有时会有许多Calayer堆叠在一起,我真的需要找到一种方法来确定用户真正想要点击的内容 我在想,如果我能以某种方式得到一个数组,其中包含指向所有包含点击点的Calayer的指针,我可以以某种方式过滤它们。但是,到目前为止,我创建阵列的唯一方法是: NSMutableArray* anArrayOfLayers = [NSMutableArray array];

我正在为Mac编写一个使用Cocoa的游戏。我目前正在实施命中测试,发现CALayer提供命中测试,但似乎没有实现alpha属性。由于我有时会有许多Calayer堆叠在一起,我真的需要找到一种方法来确定用户真正想要点击的内容

我在想,如果我能以某种方式得到一个数组,其中包含指向所有包含点击点的Calayer的指针,我可以以某种方式过滤它们。但是,到目前为止,我创建阵列的唯一方法是:

NSMutableArray* anArrayOfLayers = [NSMutableArray array];
    for (CALayer* aLayer in mapLayer.sublayers)
    {
        if ([aLayer containsPoint:mouseCoord])
            [anArrayOfLayers addObject:aLayer];
    }
然后按CALayer的z值对数组进行排序,然后检查该位置的像素是否为alpha。然而,在排序和alpha检查之间,这似乎是一个令人难以置信的性能猪。(你怎么检查阿尔法?)


有什么办法可以做到这一点吗?

我在为一个类似的问题挠头时偶然发现,CALayer在发送时使用了
containsPoint:

它的默认行为是针对边界进行测试,但我们可以覆盖它并让它检查alpha通道,只需使用CALayer的内置命中测试来处理其余部分:

- (BOOL) containsPoint:(CGPoint)p 
{
    return CGRectContainsPoint(self.bounds, p) && !ImagePointIsTransparent(self.contents, p)) return YES;
}
这里有一个关于测试单个像素的alpha的讨论

这是为了我的目的:

static BOOL ImagePointIsTransparent(CGImageRef image, CGPoint p)
{
    uint8_t alpha;

    CGContextRef context = CGBitmapContextCreate(&alpha, 1, 1, 8, 1, NULL, kCGImageAlphaOnly);
    CGContextDrawImage(context, CGRectMake(-p.x, -p.y, CGImageGetWidth(image), CGImageGetHeight(image)), image);
    CGContextRelease(context);

    return alpha == 0;
}

(如果您使用
renderInContext:
绘制CALayer而不是设置其contents属性,那么它将更加复杂。在这种情况下,这可能很有用:)

Chris,这太棒了!问:当你通过这个点时,它似乎要求它的原点在左下角和右上角。我想这是在通过这里之前必须发生的事情,对吗?(除了使用图像高度翻转y轴)我想我正在尝试确定调整的正确位置在哪里-在ImagePointIsTransparent中,或者在手势/触摸处理程序中。事实上,我想我链接到的问题是关于你在问什么-核心图形和UIKit有不同的y轴,所以我想你会想在两者之间的接口处转换。还有一个关于渲染层的不同方式(渲染所有层一次,而只是重复渲染一个像素)对性能的影响的讨论,你可能也想看看。克里斯,我刚刚意识到:你在写一个Mac应用程序。我正在写一个iOS应用程序。结果表明,当使用视网膜显示器时,该测试不起作用(在iPhone4或视网膜模式下的模拟器上)。《Quartz 2D编程指南》建议我使用UIGraphicsBeginImageContextWithOptions和较低级别的Quartz函数,因此我必须看看这是否有助于CTM等等。(这也可以解释为什么反应在视网膜上看起来“到处都是”)这是测试阿尔法的完美实现。我只是想提一下,如果一个图像在一个层内被调整大小。命中测试发生在原始图像位置,而不是调整大小的位置。最有可能的方法是将坐标从调整大小的图层转换为原始图像,但我没有找到它,因为我不需要它。这让我挂了半天电话,希望这能帮助其他人。虽然我来晚了,但我只想说,我已经制作了一个示例应用程序,提供了CALayers和CAShapeLayers(不渲染上下文:)像素级命中测试所需的所有代码供下载。它还具备高效测试或rect区域(想想选择)所需的一切。演示可以使用