0
votes

so there are some similar questions on here, but they don't really answer the questions/problem I am having.

The following explanation of my project may or may not help, I am adding it here just in case...

I am trying to build my first iOS Game, and I have built a scene using the scene editor. The scene contains a SKNode named "World". There is then a backgroundNode and a foregroundNode that are children of the world node. Everything in the scene right now, all SKSpriteNodes, are children of the backgroundNode.

In my GameScene.swift file I have variables attached to the background and foreground nodes so that I can add children to these nodes as the game progresses.

Hopefully this is clear so far...

Now I have added 5 other *.sks files to my project. These file contain scenes that I have made that will be added as children of the foreground node through code in my GameScene.swift file. The SKSpriteNodes in these scene files are placed in the foreground, but their z-position is less than the z-position of one of the background child nodes. This is because I want to have a box appear behind a light beam (the light beam is apart of the background and the box is added to the foreground). Here is a picture in case I caused any confusion Picture Of Boxes that were added to the foreground node appearing behind the lights that are children of the background node

My problem is this... I want to tap on the screen using gesture recognizers so that when I tap on the box I can then do some stuff. Trouble is that since the light beam has a greater z-position (cause of the effect I want), every time I use the atPoint(_ p: CGPoint) -> SKNode method to determine what node I tapped on I get returned the light beam node and not the box node.

How do I tap on just the box? I have tried changing the isUserInteractionEnabled property for the lights to false already, and I have tried using touchesBegan as shown in many of the other responses to similar question. I have also tried reading the swift developer documents provided by Apple, but I can't figure this out.

The code for my gesture Recognizers is below:

 //variables for gesture recognition
let tapGesture = UITapGestureRecognizer()
let swipeUpGesture = UISwipeGestureRecognizer()

//set up the tap gesture recognizer
tapGesture.addTarget(self, action: #selector(GameScene.tappedBox(_:)))
self.view!.addGestureRecognizer(tapGesture)
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1

//handles the tap event on the screen
@objc func tappedBox(_ recognizer: UITapGestureRecognizer) {

    //gets the location of the touch
    let touchLocation = recognizer.location(in: recognizer.view)
    if TESTING_TAP {
        print("The touched location is: \(touchLocation)")
    }

    //enumerates through the scenes children to see if the box I am trying to tap on can be detected (It can be detected using this just don't know how to actually detect it by tapping on the box)
    enumerateChildNodes(withName: "//Box1", using: { node, _ in
        print("We have found a single box node")
    })

    //tells me what node is returned at the tapped location
    let touchedNode = atPoint(touchLocation)
    print("The node touched was: \(String(describing: touchedNode.name))")

    //chooses which animation to run based on the game and player states
    if gameState == .waitingForTap && playerState == .idle{
        startRunning()              //starts the running animation
        unPauseAnimation()
    }else if gameState == .waitingForTap && playerState == .running {
        standStill()                //makes the player stand still
        unPauseAnimation()
    }
}

Hopefully this is enough for you guys... If you need some more code from me, or need me to clarify anything please let me know

2
Use UITouch to identify sprites.El Tomato

2 Answers

2
votes

Please read notes in the code. You can get what you want easily in spriteKit. Hope you get the answer.

     @objc func tappedBox(_ recognizer: UITapGestureRecognizer) {

     let touchLocation = recognizer.location(in: recognizer.view)

  // Before you check the position, you need to convert the location from view to Scene. That's the right location.
     let point =  (recognizer.view as! SKView).convert(touchLocation, to: self)

      print ( getNodesatPoint(point, withName: "whatever Node name"  ) )
   }

 // 2 : This function  gives you all nodes with the name you assign. If you node has a unique name, you got it.
 ///     You can change name to other properties and find out.

     private func   getNodesatPoint(_ point : CGPoint , withName name: String) -> [SKNode] {
           return self.nodes(at: point).filter{ $0.name == name}
   }
0
votes

You want to use nodesAtPoint to do a hit test and get all of your nodes that is associated with the point. Then filter the list to find the box you are looking for.

If you have a lot of layers going on, you also may want to just add an invisible layer on top of your graphics that handles nodes being touched

Your other option is to turn off isUserInteractionEnabled on everything except the boxes and then override the touch events for your boxes, but that would mean you can't use gestures like you are doing now.