【问题标题】:Mix up between UIGestureRecogniser and touchesBeganUIGestureRecogniser 和 touchesBegan 之间的混淆
【发布时间】:2016-01-11 19:26:27
【问题描述】:

我在 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()

【问题讨论】:

    标签: sprite-kit swift2 uigesturerecognizer touchesbegan


    【解决方案1】:

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

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

    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
    }
    

    【讨论】:

    • 欣赏这一点。我在实施解决方案后发现问题重复了。我的结论是,Apple 已经在后台实现了类似的功能。然而,我追踪了这个问题。它来自 Swift2 的变化。在“旧”swift中,我只是在寻找节点的前缀。
    • iOS 不会在滑动手势期间禁用单个触摸事件,因为它事先不知道手势将是滑动,直到用户的手指移动设定的距离。您可以通过在enemy 上开始滑动来测试这一点。在这种情况下,即使使用更新的hasPrefix 代码,场景也会转换。我已更新我的答案以添加 hasPrefix 测试。
    • 谢谢。这是比我更好的方法。在开始滑动时,我依靠用户避免触摸敌方节点。我遇到了第二个问题,这是由于编辑器为 hasPrefix 建议的 != nil 测试实际上意味着任何没有名称的节点都被视为敌方节点。这个问题触发了来自敌方节点的预期转换。现在这两个问题都解决了!
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2016-09-22
      • 2015-06-01
      • 2020-01-08
      • 2012-10-21
      • 2011-09-22
      • 2013-01-03
      • 2012-06-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多