【问题标题】:Hit Testing with CALayer using the alpha properties of the CALayer contents使用 CALayer 内容的 alpha 属性使用 CALayer 进行命中测试
【发布时间】:2011-02-26 00:12:14
【问题描述】:

我正在使用 Cocoa 为 Mac 编写游戏。我目前正在实施命中测试,并发现 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 检查之间,这似乎是一个令人难以置信的性能消耗。 (你甚至会如何检查 alpha?)

有什么办法吗?

【问题讨论】:

    标签: cocoa calayer


    【解决方案1】:

    我在为类似问题挠头时偶然发现的是,当您发送 hitTest: 时,CALayer 使用 containsPoint:

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

    - (BOOL) containsPoint:(CGPoint)p 
    {
        return CGRectContainsPoint(self.bounds, p) && !ImagePointIsTransparent(self.contents, p)) return YES;
    }
    

    Retrieving a pixel alpha value for a UIImage 讨论了单个像素的 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 属性,那么它会更复杂。这在这种情况下可能很有用:http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/

    【讨论】:

    • 克里斯,这太棒了!给你的问题:当通过点时,它似乎要求它的原点在左下角和右上角。我怀疑这是在通过这里之前必须发生的事情,对吧? (除了使用图像高度来翻转 y。)我想我正在尝试确定进行调整的正确位置 - 在 ImagePointIsTransparent 或手势/触摸处理程序中。
    • 碰巧,我认为我链接到的问题是关于你在问什么——Core Graphics 和 UIKit 有不同的 Y 轴,所以我想你会想在他们俩。还有一个关于渲染层的不同方式的性能影响的讨论(渲染一次与重复渲染一个像素),您可能还想查看。
    • 克里斯,我刚刚意识到:您正在编写一个 Mac 应用程序。我正在编写一个 iOS 应用程序。事实证明,当使用 Retina 显示器时,此测试不起作用(在 iPhone 4 或 Retina 模式下的模拟器上)。 Quartz 2D 编程指南建议我使用 UIGraphicsBeginImageContextWithOptions 与较低级别的 Quartz 函数,所以我必须看看这是否有助于 CTM 等等。 (这也可以解释为什么 Retina 上的响应似乎“无处不在”。)stackoverflow.com/questions/7506248/…
    • 这是测试 alpha 的完美实现。我只想提一下,如果在图层内调整图像大小。命中测试发生在原始图像位置,而不是调整大小的位置。很可能有一种方法可以将坐标从调整大小的图层转换为原始图像,但我没有找到它,因为我不需要它。它挂了我半天,希望这对其他人有帮助。
    • 虽然我迟到了,但我只想说我已经制作了一个可供下载的示例应用程序,其中包含 CALayers 像素级命中测试所需的所有必要代码作为 CAShapeLayers (不 renderInContext :)。它还具有高效测试或矩形区域(想想选择)所需的一切。演示可用here
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    相关资源
    最近更新 更多