Kyle Goslan
Kyle Goslan

Reputation: 10920

Detect touch on child node of object in SpriteKit

I have a custom class that is an SKNode, which in turn has several SKSpriteNodes in it. Is there a way I can detect touches on these child SKSpriteNodes from my game scene?

I'm working in swift

Upvotes: 11

Views: 14223

Answers (4)

Lucas Werner Kuipers
Lucas Werner Kuipers

Reputation: 190

Swift 5+

If you wish to encapsulate touch logic in a node and deal with it locally, you can simply set interaction to true in the corresponding node.

isUserInteractionEnabled = true

And then, of course, override touchesBegan to your desire.

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {}

If you still wish to receive touches in the scene when touches occur inside a child node, you can, for instance, define a protocol and property for the child node's delegate and set the scene to be it.

e.g:

final class GameScene: SKScene {
    private let childNode = ChildNode()

    override func didMove(to view: SKView) {
        addChild(childNode)
        childNode.delegate = self
    }
}

extension GameScene: TouchDelegate {}

protocol TouchDelegate {
    func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
}

final class ChildNode: SKSpriteNode {
    var delegate: TouchDelegate?

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

Upvotes: 1

Graham Perks
Graham Perks

Reputation: 23390

Examine Apple's SceneKitVehicle demo. Someone kindly ported it to Swift.

The code you want is in the GameView.swift file. In the GameView you'll see the touchesBegan override. Here's my version of it for Swift 2.1:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    guard let scene = self.overlaySKScene else {
        return
    }

    let touch = touches.first!
    let viewTouchLocation = touch.locationInView(self)
    let sceneTouchPoint = scene .convertPointFromView(viewTouchLocation)
    let touchedNode = scene.nodeAtPoint(sceneTouchPoint)

    if (touchedNode.name == "Play") {
        print("play")
    }
}

If it's not clear; the GameView is set as the app's view class by way of the Storyboard.

Upvotes: 2

cor
cor

Reputation: 627

You'll need to compare the location of your Touch to the location of your SKNode

You can get the location of your touch at one of the following methods, using locationInNode():

  • touchesBegan()
  • touchesMoved()
  • touchesEnded()

Upvotes: 0

meisenman
meisenman

Reputation: 1828

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {

   let touch = touches.anyObject() as UITouch

   let touchLocation = touch.locationInNode(self)

    if([yourSprite containsPoint: touchLocation])
    {
         //sprite contains touch
    }
}

Source: http://www.raywenderlich.com/84434/sprite-kit-swift-tutorial-beginners

Upvotes: 10

Related Questions