Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I drag and drop a sprite in Swift 3.0?

All i'm trying to do is be able to drag and drop a sprite across the screen. I've tried the following code:

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    
}
}
}

This code does work, however, when I drag the ball quite fast, I guess it detects that the "ball" no longer contains the point "location" and the ball stops, meaning I have pick the ball up again. I want the ball to be able to respond to my touches quickly, so that the ball wont stop moving. How would I do this?

like image 985
Mr_Username Avatar asked Aug 17 '16 19:08

Mr_Username


2 Answers

This is the correct way to do it in Sprite Kit. Like I said in my comment, you need to assign the moving node to an activate state, in this case I use a variable called movableNode to act is my activate state. When you touch the ball, it becomes activated by assigning it to movableNode. Then as you drag your finger, movableNode will go with the drag, Then once you release, you enter a deactivate state by setting movableNode to nil. Note that this code will only work on single touch applications, if you want to handle multitouch, then you need to track which touch is doing the dragging.

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
    }
}
like image 141
Knight0fDragon Avatar answered Oct 07 '22 15:10

Knight0fDragon


KnightOFDragon solution works just fine. I just added few lines if you don't want to move sprite centre position to position where your finger touched the screen and you would like to move sprite from its centre original position.

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
}
like image 44
MOzeb Avatar answered Oct 07 '22 14:10

MOzeb