【问题标题】:swift SpriteNode and SceneKit multiple touch gesturesswift SpriteNode 和 SceneKit 多点触控手势
【发布时间】:2020-12-12 05:28:35
【问题描述】:

我正在做一个文字游戏。为此,我使用 SceneKit 并添加一个 SpriteNodes 来表示字母图块。 这个想法是,当用户单击字母图块时,会在其周围出现一些额外的图块,并带有不同的字母选项。我的问题是关于各种交互的触摸手势。

当用户点击字母拼贴时,会显示其他拼贴。我在我的 tile SpriteNode 类中使用以下方法实现了这一点:

override func touchesBegan(_ touches:Set<UITouch> , with event: UIEvent?) {
    guard let touch = touches.first else {
        return
    }
    delegate?.updateLetter(row: row, column: column, x:xcoord, y:ycoord, useCase: 1)
}

这会正确触发显示另一个精灵节点的委托。 我想要实现的是长按从父节点中删除精灵节点。我找到了 .removeFromParent() 方法,但是我无法让它检测到长按手势。

我的理解是这种手势必须使用 UIGestureRecognizer 添加。我可以在我的 Scene 类中添加以下方法:

override func didMove(to view: SKView) {
    let longPress = UILongPressGestureRecognizer(target: self,
        action: #selector(GameScene.longPress(sender:)))
    view.addGestureRecognizer(longPress)
}
@objc func longPress(sender: UILongPressGestureRecognizer) {
    print("Long Press")

这将检测到场景中任意位置的长按。但是,我需要能够在删除它之前处理按下的节点属性。我尝试将以下内容添加到 longPress 函数中:

let location = sender.location(in: self)
let touchedNodes = nodes(at: location)
let firstTouchedNode = atPoint(location).name
touchedNodes[0].removeFromParent()

但我收到以下错误:无法将“GameScene”类型的值转换为预期的参数类型“UIView?”

这似乎有点凌乱的做事方式,因为我在不同的地方都有触摸方法。

所以我的问题是,我怎样才能保留 tile 类中的当前 touchesBegan 方法,并添加一个长按手势以能够引用和删除 spriteNode?​​p>

【问题讨论】:

    标签: swift sprite-kit uigesturerecognizer scenekit touchesbegan


    【解决方案1】:

    长按手势是连续手势,如您所见,可能会被多次调用。您是否尝试过 Recognizer.State.began、.changed、.ended?我以这种方式解决了类似的问题。

    编辑-我认为到达那里的一种方法是将您的对象放在handleTap上并挂在该对象上。然后当 LongPress 发生时,你已经有了你的节点。如果在 longPress 之前发生了一些变化,显然你需要重置。抱歉,这里有一些额外的代码,但请查看 hitTest。

    @objc func handleTap(recognizer: UITapGestureRecognizer)
        {
            let location: CGPoint = recognizer.location(in: gameScene)
            
            if(data.isAirStrikeModeOn == true)
            {
                let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
                let scenePoint = gameScene.unprojectPoint(SCNVector3(location.x, location.y, CGFloat(projectedPoint.z)))
                gameControl.airStrike(position: scenePoint)
            }
            else
            {
                let hitResults = gameScene.hitTest(location, options: hitTestOptions)
                for vHit in hitResults
                {
                    if(vHit.node.name?.prefix(5) == "Panel")
                    {
                        // May have selected an invalid panel or auto upgrade was on
                        if(gameControl.selectPanel(vPanel: vHit.node.name!) == false) { return }
                        return
                    }
                }
            }
        }
    

    【讨论】:

    • 我尝试在测试的时候放一个打印函数来确认是否调用了任何方法。当我使用给定的代码执行我的场景的长按功能时,我可以看到它被调用。我的问题是我不知道如何访问被触摸的节点或从这个函数中引用它的属性
    【解决方案2】:

    所以我对这个答案并不完全满意,但它可以满足我的需要。

    我所做的是在我的瓷砖类中添加了两个变量“touchesStart”和“touchesEnd”。 然后在 touchesBegan() 中,我使用 CACurrentMediaTime() 添加对更新 touchesStart 的调用,并通过 touchesEnded() 函数更新 touchesEnd。

    然后在 touchesEnded() 中,我从 touchesEnd 中减去 touchesStart。如果差异大于 1.0,我将调用该函数进行长按。如果小于 1.0,我调用 tap 函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-05
      • 2011-08-22
      • 1970-01-01
      相关资源
      最近更新 更多