混合使用 UIGestureRecogniser 和 touchesBegan

Mix up between UIGestureRecogniser and touchesBegan

我在 SpriteKit 场景中同时使用 UISwipeGestureRecognizertouchesBegan。 UISwipeGestureRecogniser 在 didMoveToView() 中启动:

let swipeRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("swipedRight:"))
swipeRight.direction = .Right
view.addGestureRecognizer(swipeRight)

let swipeLeft:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("swipedLeft:"))
swipeLeft.direction = .Left
view.addGestureRecognizer(swipeLeft)

touchesBegan()用于在节点被触摸时转换到另一个场景。节点由它们的名称标识,在某些情况下由它们名称的前缀标识。

if (node.name?.hasPrefix("enemy") != nil) {
    let transition = SKTransition.crossFadeWithDuration(StandardSettings.SceneManager.transitionDuration)
    let enemyScene = EnemyScene(size: self.frame.size)
                    enemyScene.scaleMode = .AspectFill
    view?.presentScene(enemyScene, transition: transition)
}

最后,还有swipedRight() 和swipedLeft() 函数。这些将 SKShapeNode 从左向右移动(或相反)。

func swipedRight(sender:UISwipeGestureRecognizer) {            
shapeNode.runAction(SKAction.moveByX(UIScreen.mainScreen().bounds.size.width * 0.5, y: 0, duration: 5.0))
}

这一切都很好,除非在滑动移动期间触摸了由其前缀标识的节点。当没有与节点接触时,shapeNode 会按预期在屏幕上移动。当有联系时,到新场景的转换代码也被调用。似乎这只发生在敌方节点被其名称前缀识别时。通过全名与字符串比较来识别的节点似乎没有这个问题。有没有办法在代码执行滑动触发方法时禁用 touchesBegan()

确定触摸事件是滑动手势还是简单触摸的一种方法是测试开始和结束触摸位置之间的距离。以下是如何执行此操作的示例。

首先,定义一个存储初始触摸位置的变量

var touchStart:CGPoint?

和一个常量来测试触摸位置之间的距离。根据需要调整此值。

let minSwipeDistance:CGFloat = 22

touchesBegan方法中,存储初始触摸位置

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        touchStart = touch.locationInNode(self)
    }
}

并在touchesEnded中,比较当前和初始触摸位置之间的距离。如果这个距离比较小,则不是滑动事件。

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first, start = touchStart {
        let location = touch.locationInNode(self)
        // Compute the distance between the two touches
        let dx = location.x - start.x
        let dy = location.y - start.y
        let distance = sqrt(dx*dx + dy*dy)
        if distance < minSwipeDistance {
            let node = nodeAtPoint(location)
            if let name = node.name where name.hasPrefix("enemy") {
                print ("transition to new scene")
            }
        }
    }
    // Reset the initial location
    touchStart = nil
}

它来自于 Swift2 的变化。在 "old" swift 中,我刚刚寻找节点的前缀... if (node.name?.hasPrefix("enemy")) 随着升级到 Swift2,我按照编辑器中的建议更改添加了 if (node.name?.hasPrefix("enemy") != nil) 我现在明白了,这实际上使前缀测试变得毫无意义。我使用的解决方案是强制声明 if (node.name!.hasPrefix("enemy")) 并注意我现在需要确保所有 SKNode 都有一个名称 属性.