如何在Swift 3.0中拖放精灵?

9
我想实现的目标是在屏幕上拖放一个精灵。我尝试了以下代码:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in (touches ) {
        let location = touch.locationInNode(self)
        if ball.containsPoint(location) {
            ball.position = location    
}
}
}

这段代码实际可用,但当我快速拖动球时,它检测到“ball”不再包含点“location”,球就停止了,这意味着我需要重新拾起球。我希望球能够迅速响应我的触摸,这样球就不会停止移动。我该怎么做?


1
因为你需要逻辑思考,如果你移动得太快,手指在进行检查时就不再触碰到球了。你需要使用touchesBegan来启动一个激活状态,使用你的containPoint代码,然后在使用touchesMoved时,只有在状态被激活时才移动球,不需要检查点,最后在touchesEnded或touchesCanceled时将其停用。 - Knight0fDragon
3个回答

18

这是在Sprite Kit中正确的方法。如我在评论中所说,您需要将移动节点分配给一个激活状态,在这种情况下,我使用一个名为movableNode的变量作为我的激活状态。当您触摸球时,通过将其分配给movableNode来激活它。然后随着手指拖动,movableNode将跟随拖动。一旦您释放,将通过将movableNode设置为nil进入非激活状态。请注意,此代码仅适用于单点触控应用程序,如果您想处理多点触控,则需要跟踪哪个接触正在拖动。

var movableNode : SKNode?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let location = touch.locationInNode(self)
        if ball.containsPoint(location) {
            movableNode = ball
            movableNode!.position = location    
        }
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first where movableNode != nil {
        movableNode!.position = touch.locationInNode(self)
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first where movableNode != nil {
        movableNode!.position = touch.locationInNode(self)
        movableNode = nil
    }
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        movableNode = nil
    }
}

如果您要点踩,请说明原因,这是正确的解决方案。 - Knight0fDragon

9

KnightOFDragon的解决方案完全有效。如果您不想将精灵中心位置移动到手指触摸屏幕的位置,并且希望从其中心原始位置移动精灵,则只需添加几行即可。

var movableNode : SKNode?
var ballStartX: CGFloat = 0.0
var ballStartY: CGFloat = 0.0

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let location = touch.location(in: self)
        if (map?.contains(location))! {
            movableNode = ball
            ballStartX =  (movableNode?.position.x)! - location.x // Location X of your sprite when touch started
            ballStartY =  (movableNode?.position.y)! - location.y // Location Y of your sprite when touch started
        }
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first, movableNode != nil {
        let location = touch.location(in: self)
        movableNode!.position = CGPoint(x: location.x+ballStartX, y: location.y+ballStartY) // Move node around with distance to your finger
    }
}

override  func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let _ = touches.first, movableNode != nil {
        movableNode = nil
    }
}
 override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
    movableNode = nil
}

太棒了。谢谢你。 - Steve
那么这基本上只会使我的节点在拖动时才能移动,对吧?因为当我点击显示器的某些部分时,节点会移动到那里。除非我在屏幕上拖动某个地方,否则我不希望节点移动。 - Dewan

-2

我有一个实现,其中我已经创建了一个UIImageView的子类,并将其称为“DraggableImage”

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        originalPosition = self.center
    }

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let position = touch.location(in: self.superview)
            self.center = CGPoint(x: position.x, y: position.y)
        }
    }

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

        self.center = originalPosition
    }

2
这怎么可能是一个答案,SKNodes和UIViews是两个不同的东西,如果你移动得很快,你仍然会遇到这个可拖动图像touchesMoved事件没有被触发的问题,因为你超出了框架。 - Knight0fDragon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接