jwade502
jwade502

Reputation: 918

How to prevent additional touch from interfering with drag location

I'm looking for help on a problem I've been stuck on for a while but cannot find an answer to.

I have a SpriteKit kids game app in which the user can drag objects (SKspriteNodes) around the screen. This is controlled in the "touches" events like so:

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    super.touchesBegan(touches, withEvent: event)

    let touch = touches.first as! UITouch
    let touchLocation = touch.locationInNode(self)

    if piece01.containsPoint(touchLocation) && piece01Placed == false && aPieceIsBeingGrabbed == false {
        piece01Grabbed = true
        aPieceIsBeingGrabbed = true
        self.piece01.zPosition = 4.0
        }
    }

   override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
    super.touchesMoved(touches, withEvent: event)

    let touch = touches.first as! UITouch
    let touchLocation = touch.locationInNode(self)

    if piece01Grabbed && piece01Placed == false {
        self.piece01.position = CGPointMake(touchLocation.x + worldScale * 120, touchLocation.y - worldScale * 80)

    }
}

My problem is that if the user touches another part of the screen while dragging a sprite, a glitch occurs and the Sprite bounces back and forth between the two touch locations and can't decide which one to stay with.

Does anyone know how I can prevent this so that the Sprite always follows the touch that it was initially grabbed by? Thanks in advance!

Upvotes: 0

Views: 183

Answers (2)

jwade502
jwade502

Reputation: 918

MaceDevs above answer is correct based on my question and works with the touchesMoved event like how I initially asked. However, I discovered that it is easier to use a gesture recognizer to handle dragging events.

So to solve this, I ended up scrapping my "touches" methods and implemented a UIPanGestureRecognizer instead.

All you have to do is set up a UIPanGestureRecognizer in didMoveToView and set its maximum number of touches to 1. If you do not set this to 1, then any additional touches will move the piece in an average direction of the touches.

//Declare "draggingPiece" variable at top of swift file
var draggingPiece: UIPanGestureRecognizer!

//...init functions...

override func didMoveToView(view: SKView) {
    //Enable the gesture recognizer
    draggingPiece = UIPanGestureRecognizer(target: self, action: Selector("dragPiece:"))
    draggingPiece.maximumNumberOfTouches = 1

    self.view?.addGestureRecognizer(draggingPiece)

}

func dragPiece(recognizer: UIPanGestureRecognizer) {
    if recognizer.state == UIGestureRecognizerState.Began {

    }else if recognizer.state == UIGestureRecognizerState.Changed {

    }else if recognizer.state == UIGestureRecognizerState.Ended {

    }
}

And then remove the gesture recognizer in willMoveFromView:

self.view?.removeGestureRecognizer(draggingPiece)

Upvotes: 1

Mason
Mason

Reputation: 271

One of the simplest ways to achieve this would be to use this (no need to implement touchesBegan):

override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent)
{
    for touch in (touches as! Set<UITouch>)
    {
        let location = touch.locationInNode(self)

        for childNode in children
        {
            if (childNode is SKSpriteNode)
            {
                let node = childNode as! SKSpriteNode

                if (CGRectContainsPoint(node.frame.expand(50.0), location))
                {
                    node.position = location
                }
            }
        }
    }
}

Where the expand extension is simply used to increase the boundaries where the touch is allowed and is defined as:

extension CGRect
{
    func expand(percent: CGFloat) -> CGRect
    {
        let deltaWidth = (percent / 100.0) * self.width
        let deltaHeight = (percent / 100.0) * self.height
        return CGRect(x: self.origin.x, y: self.origin.y, width: self.width + deltaWidth, height: self.height + deltaHeight)
    }
}

You'll probably want to add more logic to handle overlaps et cetera, but this should be a good foundation from where to start.

Hope this helps

Upvotes: 0

Related Questions