检测 SKShapeNode 上的触摸是一条线

Posted

技术标签:

【中文标题】检测 SKShapeNode 上的触摸是一条线【英文标题】:Detecting Touch on SKShapeNode that is a Line 【发布时间】:2014-07-01 03:24:00 【问题描述】:

我创建了一个 SKShapeNode 并为其提供了一个 CGPath。这是在 didMoveToView 中的 GameScene.swift 中:

let myNode = SKShapeNode()
let lineToDraw = CGPathCreateMutable()
CGPathMoveToPoint(lineToDraw, nil, 0, 0)
CGPathAddLineToPoint(lineToDraw, nil, 87, 120)
myNode.path = lineToDraw
myNode.strokeColor = SKColor.redColor()
myNode.lineWidth = 20
myNode.name = "My Node!"
world.addChild(myNode) // World is a higher-level node in my scene

这就是我在场景中再次检测触摸的方式:

override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) 
    if let touch = touches.anyObject() as? UITouch 
        if let shapeNode = nodeAtPoint(touch.locationInNode(self)) as? SKShapeNode 
            println("Touched \(shapeNode.name)")
         else 
            println("Nothing here")
        
    

线节点显示没有问题。但是,它根本没有注册 touchesEnded。

真的,我有三个模糊不清的问题:

    有没有更好的方法来创建一个 SKShapeNode,它是两点之间的一条线,而无需调用便利初始化程序?我计划子类化 SKShapeNode 以向节点添加额外的逻辑,并且子类无法访问超类的便利初始化程序。

    更重要的是,如何让场景识别那里的线节点并触发 touchesEnded?

    有没有办法,使用这种机制,我可以让它更“模糊”,所以它处理接近线的触摸,而不是在线?我最终的计划是让它更薄,但我仍然希望有一个大的触摸区。我想如果不出意外,我可以创建两个节点:一个清晰/厚,另一个红色/细,并在清晰的节点上处理触摸事件,但我想知道是否有更好的方法。

    李>

【问题讨论】:

【参考方案1】:

在回答您的主要问题时,您的 touchesEnded 方法存在问题。苹果展示的模板推荐如下布局:

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) 
        for touch: AnyObject in touches 
            let location = touch.locationInNode(self)
    

然后您可以使用此方法查看 location 值是否在行框架内(为了做到这一点,我在 didMoveToView 之外创建了“myNode”变量,以便我可以从其余部分访问它函数):

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) 
        for touch: AnyObject in touches 
            let location = touch.locationInNode(world)

            if CGRectContainsPoint(myNode.frame, location) 
                println("Touched \(myNode.name)")

             else 

                println("Nothing here")
        

    

至于“模糊”行,您可以简单地检查一个更大的 CGRect。在上面的代码中,我检查了myNode.frame,但您可以创建一个比行稍大的 CGRect 变量,这样您就可以检测到不直接击中它的触摸。

至于更简洁的代码,我目前想不出,但这并不是说没有办法。但是,我不太明白您所说的子类无法访问便捷方法是什么意思,因为只要您正确导入,它们就可以访问超类所做的任何事情。

我希望这会有所帮助。

【讨论】:

如何扩大到在屏幕上显示动态行数以进行检查?另外,为什么要这样做而不是抓住nodeAtPoint()? developer.apple.com/library/ios/documentation/GraphicsAnimation/… 建议 nodeAtPoint() 确定与点相交的顶部节点是什么。 我会在初始化时命名每一行,然后枚举它们以查看有多少被点击。至于使用nodeAtPoint(),我试过了,遇到了和你一样的问题,从来没有检测到节点。出于这个原因,我使用了 CGRectContainsPoint。 采用CGRectContainsPoint() 的方式,它会在离线不远的地方检测到触摸,因为框架是矩形,而我的线是对角线。所以它认为我正在点击“线”,因为我正在点击对角线定义的矩形。 @Reece55 我相信这种方法确实有效,但它可能无法非常准确地检测到触摸。您可能想正确地使用它,尤其是在更大的形状上以更好地测试它。它通常运行良好,没有任何问题,尽管有时线条的框架不能很好地表示实际线条本身。尽管如此,如果它对您有用,那么我很高兴能为您提供帮助!

以上是关于检测 SKShapeNode 上的触摸是一条线的主要内容,如果未能解决你的问题,请参考以下文章

检测厚 UIBezierPath 上的触摸

碰撞检测之Box-Box检测

检测整个屏幕上的触摸

Sprite 套件中的 SKShapeNode 碰撞检测未检测到碰撞

如何在Sprite-kit中画一条线

如何在 Sprite-kit 中画一条线