How do I detect if an SKSpriteNode has been touched

SwiftSprite KitTouchSkspritenodeTouchesbegan

Swift Problem Overview


I am trying to detect if my sprite node has been touched and I have no idea where to start.

let Pineapple = SKSpriteNode(imageNamed: "Pineappleimg")
Pineapple.userInteractionEnabled = true
Pineapple.position = CGPoint(x: CGRectGetMidX(self.frame) - 200, y: CGRectGetMidY(self.frame));
self.addChild(Pineapple)

Swift Solutions


Solution 1 - Swift

First set the name property of the SKSpriteNode to a string.

pineapple.name = "pineapple"
pineapple.userInteractionEnabled = false

then in touchesBegan function in the Scene

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    let touch:UITouch = touches.anyObject()! as UITouch
    let positionInScene = touch.locationInNode(self)
    let touchedNode = self.nodeAtPoint(positionInScene)
    
    if let name = touchedNode.name
    {
        if name == "pineapple"
        {
            print("Touched")
        }
    }
    
}

This is one way to do it.
You can also subclass SKSpriteNode and override the touchesBegan inside it.

class TouchableSpriteNode : SKSpriteNode
{
    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        print("touched")
    }
}

Then do

let pineapple = TouchableSpriteNode(imageNamed: "Pineappleimg")
pineapple.userInteractionEnabled = true
pineapple.position = CGPoint(x: CGRectGetMidX(self.frame) - 200, y: CGRectGetMidY(self.frame));
self.addChild(pineapple)

Solution 2 - Swift

If you are looking only for a few nodes that can be touched (e.g., the "Continue" or "Exit" labels in a game UI), this might be an alternative but very simple solution:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch = touches.first!
    if myNode.containsPoint(touch.locationInNode(self)) {
        print("touched")
    }
}

Solution 3 - Swift

Update for Swift Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1) and XCode Version 8.2.1 (8C1002):

> Value of type 'Set' has no member 'anyObject'

> 'locationInNode' has been renamed to 'location(in:)'

> 'nodeAtPoint' has been renamed to 'atPoint(_:)'

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        let location = touch.location(in: self)
        let node : SKNode = self.atPoint(location)
        if node.name == "myNodeName" {
            print("Hello")
        }
    }
}

Solution 4 - Swift

This will detect touches in Xcode 9.2 Swift 4.0

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
    let touch:UITouch = touches.first!
    let positionInScene = touch.location(in: self)
    let touchedNode = self.atPoint(positionInScene)
    
    if let name = touchedNode.name
    {
        if name == "playLbl"
        {
            print("playLbl Touched")
        }
    }
    
}

Solution 5 - Swift

swift 5 update

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        for touch in touches {
            let location = touch.location(in: self)
            let touchedNode = self.nodes(at: location)
            for node in touchedNode {
                if node.name == "play_button" {
                    startGame()
                }
            }
        }
    }

Solution 6 - Swift

Implement touchesBegan method that is called when a touch begins. Alternatively you can do this in touchesEnded as well.

override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
{
    let touch = touches.anyObject() as UITouch
    let location = touch.locationInNode(self)
    let nodes = self.nodesAtPoint(location)
    
    for node in nodes
    {
        if node.name == "youNodeName"
        {
            // Node tapped
            // Do something
            
            break
        }
    }
}

Solution 7 - Swift

Swift 3 answer which embeds touch functionality in subclass of SKSpriteNode:

class SpriteSub: SKSpriteNode {
 
    init() {
        super.init(texture: nil, color: UIColor.red, size: CGSize(width: 50, height: 50))
        isUserInteractionEnabled = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    ...
   
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("touch!")
    }
 
}

Solution 8 - Swift

Use this piece of code to detect touch on SKSpriteNode

if(nodeAtPoint(location) == node){


                    
}

Solution 9 - Swift

Update for Swift 3.0 and XCode 7.3.1. I've got a SKShapeNode that I've derived to a new class and inserted it on the Scene. When I want to detect this object it I check as follows:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
   
    for touch in touches {
   
        let location = touch.locationInNode(self)
        let nodes = self.nodesAtPoint(location)
        
        for node in nodes
        {
            if node is SKNodeDerivedNode
            {
                NSLog("Touch a SKNodeDerivedNode")
                break
            }
        }
    }
}

Solution 10 - Swift

This is the way I use in Swift 4 to find if there is a touch in a specific type of node:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else {
        return
    }
    let touchPosition = touch.location(in: self)
    let touchedNodes = nodes(at: touchPosition)
    for node in touchedNodes {
        if let nodoTouched = node as? YourNodeType {
            // touched!
        }
    }
}

Solution 11 - Swift

If you have still not got your sprite to work even after subclassing SKSpriteNode, you most likely forgot to add node.isUserInteractionEnabled = true when you initialise it!

This allows touchesBegan(_:with:) to be called, as you can now interact with the node.


Example:

node = MySprite(texture: texture, size: size)
node.isUserInteractionEnabled = true

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJames BrennanView Question on Stackoverflow
Solution 1 - SwiftrakeshbsView Answer on Stackoverflow
Solution 2 - SwiftFlorian BlumView Answer on Stackoverflow
Solution 3 - SwiftAlexandr LihonosovView Answer on Stackoverflow
Solution 4 - Swiftuplearned.comView Answer on Stackoverflow
Solution 5 - SwiftMost WantedView Answer on Stackoverflow
Solution 6 - SwiftRafa de KingView Answer on Stackoverflow
Solution 7 - SwiftCrashalotView Answer on Stackoverflow
Solution 8 - Swiftzbz.lvlvView Answer on Stackoverflow
Solution 9 - SwiftbownieView Answer on Stackoverflow
Solution 10 - SwiftabanetView Answer on Stackoverflow
Solution 11 - SwiftGeorgeView Answer on Stackoverflow