touchesMoved when two nodes across swift - ios

I had a problem with movning some nodes around but I found a way (finally) but then I faced a problem which is : when two nodes gets across the touch will move from one node to the other ! but what I want is when I touch a node I will move it until I move my finger from the screen
here is my code :
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
var location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if node == firstCard{
firstCard.position = location
}else if node == secondCard{
secondCard.position = location
println("Second Card Location")
println(secondCard.position)
}else{
println("Test")
}
}
}

You need to keep track of the SKNode the finger touched in touchesBegan
First thing to remember is the the same UITouch object is returned for each finger in touchesMoved with different locations. So we can keep track of the each touch in the node using a touchTracker dictionary.
var touchTracker : [UITouch : SKNode] = [:]
Also give a name to each card, so that we can keep track of the nodes that need to be moved. For example.
card1.name = "card"
card2.name = "card"
In touchesBegan, we will add the node that is under the touch to the touchTracker.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if (node.name == "card") {
touchTracker[touch as UITouch] = node
}
}
}
When a touch is moved inside touchesMoved, we will get the node back from the touchTracker and update its position.
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
let location = touch.locationInNode(self)
let node = touchTracker[touch as UITouch]
node?.position = location
}
}
In touchesEnded, we update the final position again, and remove the touch key-value pair from touchTracker.
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
let location = touch.locationInNode(self)
let node = touchTracker[touch as UITouch]
node?.position = location
touchTracker.removeValueForKey(touch as UITouch)
}
}

Related

multitouch in iOS [duplicate]

So I've been messing around trying to get the coordinates of touches on the screen. So far I can get the coordinates of one touch with this:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject()! as UITouch
let location = touch.locationInView(self.view)
println(location)
}
But when touching with two fingers I only get the coordinates of the first touch. Multi-touch works (I tested with this little tutorial: http://www.techotopia.com/index.php/An_Example_Swift_iOS_8_Touch,_Multitouch_and_Tap_Application). So my question is, how do I get the coordinates of the second (and third, fourth...) touch?
** Updated to Swift 4 and Xcode 9 (8 Oct 2017) **
First of all, remember to enable multi-touch events by setting
self.view.isMultipleTouchEnabled = true
in your UIViewController's code, or using the appropriate storyboard option in Xcode:
Otherwise you'll always get a single touch in touchesBegan (see documentation here).
Then, inside touchesBegan, iterate over the set of touches to get their coordinates:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
print(location)
}
}
the given touches argument is a set of detected touches.
You only see one touch because you select one of the touches with :
touches.anyObject() // Selects a random object (touch) from the set
In order to get all touches iterate the given set
for obj in touches.allObjects {
let touch = obj as UITouch
let location = touch.locationInView(self.view)
println(location)
}
You have to iterate over the different touches. That way you can access every touch.
for touch in touches{
//Handle touch
let touchLocation = touch.locationInView(self.view)
}
In Swift 1.2 this has changed, and touchesBegan now provides a Set of NSObjects.
To iterate through them, cast the touches collection as a Set of UITouch objects as follows:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
var touchSet = touches as! Set<UITouch>
for touch in touchSet{
let location = touch.locationInView(self.view)
println(location)
}
}
For Swift 3, based on #Andrew's answer :
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touchSet = touches
for touch in touchSet{
let location = touch.location(in: self.view)
print(location)
}
}
EDIT, My bad, that's not answering your question, had the same problem and someone linked me to this previous answer :
Anyway, I had to change few things to make it works in swift 3, here is my current code :
var fingers = [String?](repeating: nil, count:5)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
for touch in touches{
let point = touch.location(in: self.view)
for (index,finger) in fingers.enumerated() {
if finger == nil {
fingers[index] = String(format: "%p", touch)
print("finger \(index+1): x=\(point.x) , y=\(point.y)")
break
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
for touch in touches {
let point = touch.location(in: self.view)
for (index,finger) in fingers.enumerated() {
if let finger = finger, finger == String(format: "%p", touch) {
print("finger \(index+1): x=\(point.x) , y=\(point.y)")
break
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
for touch in touches {
for (index,finger) in fingers.enumerated() {
if let finger = finger, finger == String(format: "%p", touch) {
fingers[index] = nil
break
}
}
}
}
I still have a little problem but I think it's linked to my GestureRecognizer in my code.
But that should do the trick.
It will print you the coordinate of each point in your consol.
In Swift 3,4
Identify touch pointer by its hash:
// SmallDraw
func pointerHashFromTouch(_ touch:UITouch) -> Int {
return Unmanaged.passUnretained(touch).toOpaque().hashValue
}

How to speed up the movement of the object?

In the scene of a finger you can move the object. But if you just speed up the movement of the finger on the screen - the object remains in place. Is it possible to accelerate the speed of its movement? Duration is already set to 0
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
let node = self.nodeAtPoint(touchLocation)
if (node.name == "circle") {
let moveAction = SKAction.moveTo(touchLocation, duration: 0)
figureUser.runAction(moveAction)
}
}
Your problem is not the speed, your problem is you are moving so fast on the screen, that your touch is not recognizing a node underneath it anymore because the node is physically not underneath it. How you handle this problem is on the touch begin event, you check for a node, and assign this node to a variable. Then on the touch move event, update the new variable. Finally on touch end, clear the variable. Note, you would need to handle this code for things like multi touch
var movingNode : SKNode?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
let node = self.nodeAtPoint(touchLocation)
if (node.name == "circle") {
movingNode = node
let moveAction = SKAction.moveTo(touchLocation, duration: 0)
figureUser.runAction(moveAction)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
let moveAction = SKAction.moveTo(touchLocation, duration: 0)
//at this point I am lost, how does node even relate here,
//is figureUser suppose to be node?
figureUser.runAction(moveAction)
}

Identify all nodes at same location

I have a iOS app that draws a grid of sprites on screen. I then have another sprite representing a colour which I can drag and drop over the grid. My question is how do I identify which sprite on the grid it was dragged onto?
Ultimately I want to allow a user to drag a colour sprite over another sprite, so I can change the colour, as per the users selection.
The code below only returns the 2nd sprite (the top one) at the location, whereas I need to identify both sprites at that location.
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
{
print("tocuhes ended")
for touch in touches
{
let location = touch.locationInNode(self)
let nodeAtLocation = self.nodeAtPoint(location)
let nodeName = nodeAtLocation.name
print("Node Name \(nodeName)")
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches
{
let location = touch.locationInNode(self)
let nodesAtLocation = self.nodesAtPoint(location)
for node in nodesAtLocation {
let nodeName = node.name
print("Node Name \(nodeName)")
}
}
}

Detect touch on SKNode (swift)

I have created a container node to put in all my SKSpriteNodes that need to be moved all in one touch, I can detect touches on them normally in iOS 8 but in iOS 7 I can only detect touches on my main node and when I touch an SKSpriteNode that it's in the container node nothing happens.. How can I fix this?
let lvlsNode = SKNode()
override func didMoveToView(view: SKView) {
self.addChild(lvlsNode)
axe = SKSpriteNode(imageNamed:"axe")
axe.anchorPoint = CGPointMake(1, 0)
axe.size = CGSizeMake(axe.size.width/1.4, axe.size.height/1.4)
axe.position = CGPointMake(0+screenWidth/7, shield.position.y-shield.size.width*1.4)
axe.zPosition = 12
axe.name = "axe"
lvlsNode.addChild(axe)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if node.name == "axe" {
// do something.... this work in iOS8 but not in iOS 7.1
}
Yournode.name = "nodeX"
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first as UITouch!
if atPoint((touch?.location(in: self))!).name == Yournode.name {
//Your code
}
}

(Swift + Spritekit) - remove node and its data entirely

I'm working a little game for iOS.
I've a SKSpriteNode in my scene - when I remove it with "removeFromParent" and touch the area it was last in, I still get the function.
My code is as following:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if tapToPlayNode.containsPoint(location){
tapToPlayNode.removeFromParent()
startNewGame()
}
}
}
func startNewGame(){
//Starts a new game with resetted values and characters in position
println("Ready.. set.. GO!")
//Shows the ui (value 1)
toggleUiWithValue(1)
}
In other words, I get "Ready.. set.. GO!" output when I touch the area even after it was deleted.
Any clues?
Bests,
Your tapToPlayNode is still retained by self and is removed from it's parent.
You should make it optional var tapToPlayNode:SKSpriteNode?and nil it after remove it from it's parent like this:
if let playNode = self.tapToPlayNode {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if playNode.containsPoint(location) {
playNode.removeFromParent()
startNewGame()
self.tapToPlayNode = nil // il it here!
break
}
}
}
You can also avoid to keep a reference of your tapToPlayNode and give it a name when initializing it like this:
node.name = #"tapToPlayNodeName"
// Add node to scene and do not keep a var to hold it!
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
// Retrieve the ode here
let tapToPlayNode = container.childNodeWithName("tapToPlayNodeName")!
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if tapToPlayNode.containsPoint(location){
tapToPlayNode.removeFromParent()
startNewGame()
}
}
}

Resources