我首先声明了两个skspritenodes,handle和blade,并添加handle作为self的子元素,blade作为handle的子元素

var handle = SKSpriteNode(imageNamed: "Handle.png")
var blade = SKSpriteNode(imageNamed: "Blade.png")

override func didMoveToView(view: SKView) {

    handle.position = CGPointMake(self.size.width / 2, self.size.height / 14)
    blade.position = CGPointMake(0, 124)

    self.addChild(Handle)
    Handle.addChild(Blade)
}

当我单击句柄时,它会打印到控制台“handle was clicked”,但是当我单击刀片时,它也会打印“handle was clicked”。很明显,刀片是手柄的子对象,但我如何才能做到这样,当我点击刀片时,它会打印“刀片被点击”?
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    for touch in (touches as! Set<UITouch>) {
        let location = touch.locationInNode(self)
        if (Handle.containsPoint(location)){
            NSLog("Handle was clicked")
        }
        else if (Blade.containsPoint(location)){
            NSLog("Blade was clicked")
        }

    }
}

最佳答案

确定用户是触摸刀柄还是刀刃是相当简单的,但有一些注意事项。以下假设为1。当zRotation = 0,2时,剑图像面向右侧。剑的anchorPoint是(0,0.5)和3。剑(刀柄)是一个精灵节点。将精灵添加到另一个精灵时,父级帧的大小将展开以包含子节点。这就是为什么你对Handle.containsPoint的测试是正确的,无论你在哪里点击剑。
下图显示了一个剑灵,剑柄(左)为深灰色,剑刃为浅灰色。剑周围的黑色矩形代表精灵的框架,圆圈代表用户触摸的位置。标记为a的线的长度是从接触点到剑底部的距离。我们可以测试这个距离,看看用户是否触摸了手柄(如果a <= handleLength)或刀片(如果a > handleLength)。当zRotation = 0a = x时,测试是x <= handleLength,剑的底部是x = 0
下图中,剑旋转90度(即zRotation = M_PI_2)。同样,如果a <= handleLength,则用户触摸手柄,否则用户触摸刀片。唯一的区别是a现在是y值,而不是由于剑的旋转而x。在这两种情况下,可以使用帧的边界框来检测用户是否触碰了剑。
但是,当精灵旋转45度时,其框架会自动展开以包围精灵,如下图中的黑色矩形所示。因此,当用户触摸矩形中的任何地方时,测试if sprite.frame.contains(location)将为真。这可能导致用户在触摸位置相对远离剑时(即距离b较大时)拿起剑。如果我们希望最大接触距离在所有旋转角度上都是相同的,则需要额外的测试。
好消息是sprite工具包提供了一种从一个坐标系转换到另一个坐标系的方法。在这种情况下,我们需要从场景坐标转换为剑坐标。这大大简化了问题,因为它还将点旋转到新的坐标系。将场景坐标转换为剑坐标后,转换后的触控位置的xy值与所有旋转角度上的距离ab值相同!现在我们知道了ab,我们可以确定触摸距离剑有多近,以及用户是触摸刀柄还是刀刃。
从上面可以实现以下代码:

    let location = touch.locationInNode(self)
    // Check if the user touched inside of the sword's frame (see Figure 1-3)
    if (sword.frame.contains(location)) {
        // Convert the touch location from scene to sword coordinates
        let point = sword.convertPoint(location, fromNode: self)
        // Check if the user touched any part of the sword. Note that a = point.x and b = point.y
         if (fabs(point.y) < sword.size.height/2 + touchTolerance) {
             // Check if the user touched the handle
             if (point.x <= handleLength) {
                 println("touched handle")
             }
             else {
                 println("touched blade")
             }
        }
    }

关于swift - 如何使touch.locationInNode()识别节点及其子节点之间的区别?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31373066/

10-15 15:13