我首先声明了两个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 = 0
,a = x
时,测试是x <= handleLength
,剑的底部是x = 0
。
下图中,剑旋转90度(即zRotation = M_PI_2
)。同样,如果a <= handleLength
,则用户触摸手柄,否则用户触摸刀片。唯一的区别是a
现在是y
值,而不是由于剑的旋转而x
。在这两种情况下,可以使用帧的边界框来检测用户是否触碰了剑。
但是,当精灵旋转45度时,其框架会自动展开以包围精灵,如下图中的黑色矩形所示。因此,当用户触摸矩形中的任何地方时,测试if sprite.frame.contains(location)
将为真。这可能导致用户在触摸位置相对远离剑时(即距离b
较大时)拿起剑。如果我们希望最大接触距离在所有旋转角度上都是相同的,则需要额外的测试。
好消息是sprite工具包提供了一种从一个坐标系转换到另一个坐标系的方法。在这种情况下,我们需要从场景坐标转换为剑坐标。这大大简化了问题,因为它还将点旋转到新的坐标系。将场景坐标转换为剑坐标后,转换后的触控位置的x
和y
值与所有旋转角度上的距离a
和b
值相同!现在我们知道了a
和b
,我们可以确定触摸距离剑有多近,以及用户是触摸刀柄还是刀刃。
从上面可以实现以下代码:
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/