首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有CAShapeLayer的HitTest不起作用

带有CAShapeLayer的HitTest不起作用
EN

Stack Overflow用户
提问于 2013-06-09 19:02:42
回答 2查看 1.1K关注 0票数 1

我使用下面的代码来检查玩家的点是否在圆形区域内:

代码语言:javascript
复制
if ([circle.presentationLayer hitTest:player.position])
{
    NSLog(@"hit");
}

我的圈子是一个CAShapeLayer:

代码语言:javascript
复制
CAShapeLayer *circle = [CAShapeLayer layer];
CGFloat radius = 50; 
[circle setMasksToBounds:YES];
[circle setBackgroundColor:[UIColor redColor].CGColor];
[circle setCornerRadius:radius1];
[circle setBounds:CGRectMake(0.0f, 0.0f, radius *2, radius *2)];
[self.view.layer addSublayer:circle];

碰撞检测以这种方式工作得非常好。

现在我不想用一个圆形图层来测试玩家的位置,而是用一个沿着自定义路径绘制的CAShapeLayer:

代码语言:javascript
复制
CAShapeLayer *customLayer = [CAShapeLayer layer];
customLayer.path = customPath.CGPath;
customLayer.fillColor = [UIColor yellowColor].CGColor;
customLayer.shouldRasterize = YES;
customLayer.opacity = 0.2;
[self.view.layer addSublayer: customLayer];

当我想用自定义图层测试玩家的位置时,hittest不再起作用了。

我该如何解决这个问题?

EN

回答 2

Stack Overflow用户

发布于 2013-06-10 00:19:12

您是否将位置转换为正确的相对位置?

例如:

代码语言:javascript
复制
CGPoint layerPoint = [[dynamicView layer] convertPoint:touchLocation toLayer:sublayer];

另外,也许你需要CGPathContainsPoint

代码语言:javascript
复制
if(CGPathContainsPoint(shapeLayer.path, 0, layerPoint, YES))
{
票数 2
EN

Stack Overflow用户

发布于 2017-02-10 06:47:07

您指定的是圆的边界/帧,但不是bezier路径的边界/帧。我不知道这一点,直到我自己偶然发现了它,但是当你创建一个形状并为CAShapeLayer()分配一个路径时,你必须分配CALayer的框架(或者单独的位置和边界),因为根据苹果的文档,CALayer()的框架默认是一个CGZeroRect,当你设置路径时不会自动更新。hitTest()基于position+bounds (或帧),因此失败。文档中写道:

/*返回包含点'p‘的层的最远的后代。*同级按从上到下的顺序进行搜索。'p‘被定义为*接收器最近的祖先的坐标空间中的*不是CATransformLayer (变换层没有2D *坐标空间,可以在其中指定点)。*/

可空*)hitTest:(CGPoint)p; (

  • (可空CALayer nullable

如果层的边界包含点'p‘,则/*返回true。*/

  • (BOOL)containsPoint:(CGPoint)p;

一个快速的单元测试显示了这一点(扩展CGPath很有用,包含在后面):

代码语言:javascript
复制
func testShapeLayer() {
    let layer = CAShapeLayer()
    let bezier = NSBezierPath(rect: NSMakeRect(0,0,10,10))
    layer.path = bezier.CGPath
    // remove the following line to FAIL the test
    layer.frame = NSMakeRect(0,0,10,10) 
    XCTAssertNotNil(layer.hitTest(CGPoint(x:5,y:5)))
    XCTAssertTrue(layer.contains(CGPoint(x:5,y:5)))
}

extension NSBezierPath {

public var CGPath: CGPath {
    let path = CGMutablePath()
    var points = [CGPoint](repeating: .zero, count: 3)
    for i in 0 ..< self.elementCount {
        let type = self.element(at: i, associatedPoints: &points)
        switch type {
        case .moveToBezierPathElement: path.move(to: CGPoint(x: points[0].x, y: points[0].y) )
        case .lineToBezierPathElement: path.addLine(to: CGPoint(x: points[0].x, y: points[0].y) )
        case .curveToBezierPathElement: path.addCurve(      to: CGPoint(x: points[2].x, y: points[2].y),
                                                            control1: CGPoint(x: points[0].x, y: points[0].y),
                                                            control2: CGPoint(x: points[1].x, y: points[1].y) )
        case .closePathBezierPathElement: path.closeSubpath()
        }
    }
    return path
}

}

然而,这可能不是您想要的:您希望将路径用于hitTesting(),而不仅仅是框架。因此,我可能会在您的hitTesting例程中添加一个扩展:如果命中CAShapeLayer(),这意味着它在框架内,那么您可以更具体地使用CGPathContainsPoint()检查,就像前面提到的另一个答案一样。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17008933

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档