【问题标题】:how to detect touch on node如何检测节点上的触摸
【发布时间】:2017-11-20 19:24:17
【问题描述】:

我有一个应用程序,它每 1 秒在屏幕上生成一个球。现在,我希望用户触摸那些使它们消失的球(removeFromParent())。据我了解,我必须通过 touchesBegan 设置触摸功能,我这样做了,这是我的代码:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch: AnyObject in touches{
        let positionOfTouch = touch.location(in: self)
        enumerateChildNodes(withName: "BALL") { (node: SKNode, nil) in
            if positionOfTouch == node.position {
                print("just touched the ball")
            }
            else{
                print("error")
            }
        }
    }

问题是,当我触摸屏幕/球时,控制台打印 error 而不是 just touch the ball,这意味着我的代码不起作用。此外,控制台将错误消息打印为我认为的球数。我不明白我做错了什么以及如何真正设置此功能。 这是我的 createBall 函数,它从我的 BallNode 类(类型 SKShapeNode)中实现:

    func createBall(){
    let ball = BallNode(radius: 65)
    print(ball.Name)
    print(ball._subName!)

    ball.position.y = ((frame.size.height) - 200)
    let ballXPosition = arc4random_uniform(UInt32(frame.size.width)) // set the ball a randon position from the top of the screen
    ball.position.x = CGFloat(ballXPosition)

    ball.physicsBody?.categoryBitMask = PhysicsCategory.ball // ball's category bitMask
    ball.physicsBody?.collisionBitMask = PhysicsCategory.ball // prevent objects from intersecting
    ball.physicsBody?.contactTestBitMask = PhysicsCategory.topBorder // when need to know if two objects touch each other

    addChild(ball)

}

你能帮我解决这个问题吗?因为我对 swift 很陌生,所以我也想得到一些关于这种触摸检测的解释(以及一般的触摸 - 苹果文档很差)。

【问题讨论】:

标签: swift sprite-kit uitouch touchesbegan


【解决方案1】:

每次您触摸屏幕时,您都会循环浏览所有球,看看您是否正在触摸其中一个。如果屏幕上有 50 个球,它会遍历所有球以查看您是否正在触摸 1。这不是确定您是否正在触摸 1 的有效方法。

有很多方法可以做到这一点,但我要做的是在 Ball 类中处理触摸。这样您就不必弄清楚您是否正在触摸一个球以及它可能是哪个。

对协议的解释(尽我所能)现在可能看起来有点多,但是你学习和理解协议的速度越快,你就会越好 (IMO)。

在这个例子中,我们将使用一个协议来设置一个委托 BallNode 类。协议是一组用户定义的“规则”,必须 后跟您指定的符合该协议的任何类。 在我的示例中,我声明一个类要符合 BallNodeDelegate 协议必须包含 didClick 函数。当你 在 GameScene 之后添加 BallNodeDelegate 你说这个 类将符合该协议。所以如果在 GameScene 中你做了 没有 didClick 函数会导致错误。这一切都放入 这样您就可以轻松地在您的 BallNode 实例和您的 GameScene 类(无需通过 围绕对每个 BallNode 的 GameScene 的引用)。每个 BallNode 然后有一个委托(GameScene),您可以将其传回 信息。

在你的 BallNode 类中确保你有isUserInteraction = true

在 BallNode 类之外创建一个将触摸信息发送回 GameScene 的协议

protocol BallNodeDelegate: class {
    func didClick(ball: BallNode)
}

在 BallNode 类中创建一个委托变量

weak var delegate: BallNodeDelegate!

开始给你动动一下 BallNode 类

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    self.delegate?.didClick(ball: self)
}

在 GameScene 中添加对 BallNode 协议的遵从性

class GameScene: SKScene, BallNodeDelegate

在 GameScene 中创建 Ball 时,确保将其设置为委托

let ball = BallNode()
ball.delegate = self

在 GameScene 中添加巢。处理点击的函数

func didClick(ball: BallNode) {
    print("clicked ball")
}

【讨论】:

  • 你能解释一下为什么要使用协议吗?我刚刚在 apple doc 上读到过它,但我并不真正了解它的用途
  • 确定我已经添加并编辑了我的答案,希望能帮助您理解协议
  • 哇!它的Wirkung真棒!非常感谢!你有关于“委托”的教程/解释吗?
  • 还有一件事,我不太明白你在'ball.delegate = self'这行做了什么,那个'self'属于哪里?
  • 自己就是你的游戏场景。这就是将 2 个类绑定在一起的原因
【解决方案2】:

您正在比较 exact 接触点与节点的 exact 位置,这不太可能是相同的。

if positionOfTouch == node.position {

相反,您需要测试用户的触摸是否足够接近到球的位置。

一种选择是使用SKNodecontains 函数,它会为您处理这个问题。

if node.contains(positionOfTouch) {

旁注:您可能希望使用SKSpriteNode 而不是SKShapeNode,因为SKShapeNode 在SpriteKit 中的性能很差。

【讨论】:

  • 关于你的旁注:你所说的“SpriteKit 表现不佳”是什么意思?
  • 如果场景中同时有很多形状节点,您将在功能较弱的设备上获得较低的帧速率。见stackoverflow.com/q/23344235/6658553
  • 其实我现在不在电脑前,我会尽快查看。 Tnx!
【解决方案3】:

查看在SKNode 中定义的nodes(at:CGPoint) 以检索触摸位置处的节点列表。不过,您需要使用convertPoint(fromView) 在视图坐标和场景坐标之间进行转换。文档 herehere

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多