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
"Apprequests" Dialog Reports Success, Recipients Receive Nothing
Highlight Just the Text in a Uilabel
Convert an Uiimage in a Texture
Launch Other Application Without Url Schema in Iphone
Change the Root View of Uihostingcontroller in Swiftui
How to Build Boost-Libraries for Iphone
Make Uicollectionview Zoomable
iOS 11 Layout Guidance About Safe Area for iPhone X
Selecting a Word in a Uitextview
Can't Submit Apps to Appstore: Error Itms-90534: "Invalid Toolchain
Combining 'And' and 'Or' Condition in Nspredicate
Open Installed Pwa from External Url
Apple Push Notification Limitation
Avspeechsynthesizer in Background Mode