Detect Touch on Child Node of Object in Spritekit

Detect touch on child node of object in SpriteKit

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

Detect touch on child node of object in SceneKit

To fix this issue I recommend to read next topic from Apple:

https://developer.apple.com/documentation/scenekit/scnhittestoption

General idea:

func registerGestureRecognizer() {
let tap = UITapGestureRecognizer(target: self, action: #selector(search))
self.sceneView.addGestureRecognizer(tap)
}

@objc func search(sender: UITapGestureRecognizer) {

let sceneView = sender.view as! ARSCNView
let location = sender.location(in: sceneView)
let results = sceneView.hitTest(location, options: [SCNHitTestOption.searchMode : 1])

guard sender.state == .ended else { return }

for result in results.filter( { $0.node.name == "Your node name" }) {
// do manipulations
}
}

Hope it helps!
Best regards.

How to check if a child node has been touched Swift 3

In which class did you implement this method?

If it was in SKNode itself, you simply do:

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

self.removeFromParent()

}

However, if this method is in SKScene, this way that was implemented would probably not work. Because child.position returns a point (x, y) where the touch was made. And you're trying to compare the touch point and position of the SKNode (center point), it's unlikely to work.

Instead of using this way, try using .nodeAtPoint, a method of SKScene.

For this you will need to put a value in the 'name' property of your SKNode:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touch")
let touch = touches.first!
let positionInScene = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(positionInScene)

if let name = touchedNode.name
{
if name == "your-node-name"
{
touchedNode.removeFromParent()
}
}

}

Font: How do I detect if an SKSpriteNode has been touched

How do i detect a touch location in SpriteKit?

When you create a new project and choose Game (SpriteKit game) if you look inside you will see that there is already shown how you handle touches:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */

for touch in touches {
let location = touch.locationInNode(self)

let sprite = SKSpriteNode(imageNamed:"Spaceship")

sprite.xScale = 0.5
sprite.yScale = 0.5
sprite.position = location

let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)

sprite.runAction(SKAction.repeatActionForever(action))

self.addChild(sprite)
}
}

As you can see, there is a variable location which represent the touch location in the scene's coordinate system.

How do I detect if an SKSpriteNode has been touched

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)

How to detect touches on a skspritenode created in a separate scene using a custom class of that node

There is a good explanation in this answer that should be clear your ideas about SKS files and subclassing.
About your code it is a good habit to use uppercase letter for the class names, in your case I prefer to use class Tree instead of class tree.
About your second issue, you can use userData to transfer your object from a scene to another as explained below in my example:

import SpriteKit
class GameScene: SKScene {
private var label : SKLabelNode?
var tree : Tree!
override func didMove(to view: SKView) {
self.label = self.childNode(withName: "//helloLabel") as? SKLabelNode
if let label = self.label {
label.alpha = 0.0
label.run(SKAction.fadeIn(withDuration: 2.0))
}
self.isUserInteractionEnabled = true
tree = Tree()
tree.name = "tree"
addChild(tree)
tree.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let pointOfTouch = touch.location(in: self)
let nodeUserTapped = atPoint(pointOfTouch)
if nodeUserTapped.name == "tree" {
tree.removeFromParent()
let sceneToMoveTo = Scene2.init(size: self.size)
sceneToMoveTo.userData = NSMutableDictionary()
sceneToMoveTo.userData?.setObject(tree, forKey: "tree" as NSCopying)
let gameTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: gameTransition)

}
}
}
}
class Scene2: SKScene {
var tree:Tree!
override func didMove(to view: SKView) {
print("This is the scene: \(type(of:self))")
guard let previousValue = self.userData?.value(forKey: "tree") else { return }
if previousValue is Tree {
tree = previousValue as! Tree
addChild(tree)
tree.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let pointOfTouch = touch.location(in: self)
let nodeUserTapped = atPoint(pointOfTouch)
if nodeUserTapped.name == "tree" {
tree.removeFromParent()
if let sceneToMoveTo = SKScene(fileNamed: "GameScene") {
sceneToMoveTo.scaleMode = .aspectFill
sceneToMoveTo.userData = NSMutableDictionary()
sceneToMoveTo.userData?.setObject(tree, forKey: "tree" as NSCopying)
let gameTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: gameTransition)
}
}
}
}
}

As you can read I've the control of touches both in my parent class and in my node, this can be made possible by changing the touchesBegan method of your custom SKSpriteNode as:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
print("touched!")
}
guard let parent = self.parent else { return }
parent.touchesBegan(touches, with: event)
}

Remember that you should extend this approach also to the other touches method if you want to use them..

Cannot detect touch on falling SKShapeNode // SpriteKite

My suspicion is that your problem stems from the fact that atPoint returns an SKNode. You have two ways of getting the topmost node:

if atPoint(touch.location(in: self)) == childNode(withName: "bomb"){
//run your code
}

That's fine for individual nodes. Personally, I like using a subclass, so I would use

class Bomb: SKShapeNode

and simply see whether the topmost node under my touch can be cast to Bomb.

if let bomb = atPoint(touch.location(in: self)) as? Bomb {
//...
}

This lets you move your bomb-typical settings into the subclass and makes for more readable code overall.



Related Topics



Leave a reply



Submit