Reputation: 918
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
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
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