1

I have reviewed countless references to try to understand why my scene is not behaving the way i expected it to, such as this.

Here is my very simple SKScene (2 child nodes):

  • The scene has a SpriteNode (which covers the entire scene as a background image). This has a zPosition = 0.
  • The scene has a 2nd node (SKNode) which itself has another child (up to 2 levels). This has a zPosiiton - 2.
  • ALL nodes have .userInteractionEnabled = false

Issue:

When i click anywhere all i see is that the 1st child (SpriteNode) is touched. The 2nd child (SKNode) is never touch-detected.

Note that the z-ordering of the Nodes are being rendered as I expect them. It is the touch-detection that doesnt appear to be working.

Snippet of my touchesBegan method:

       for touch in touches {
            let touchLocation = touch.locationInNode(self)
            let sceneTouchPoint = self.convertPointToView(touchLocation)
            let touchedNode = self.nodeAtPoint(sceneTouchPoint)
            if (touchedNode.name != nil) {
                print("Touched = \(touchedNode.name! as String)")
            }
        }
Community
  • 1
  • 1
AlvinfromDiaspar
  • 6,611
  • 13
  • 75
  • 140
  • You said userInteractionEnabled is false, no touches should be recognized – Knight0fDragon Sep 14 '16 at 15:57
  • From what i've read (and tested myself), setting this property to TRUE gives unintuitive results. Ex: If this is true, then the node is NOT detected in my SKScene's touchedBegan method. – AlvinfromDiaspar Sep 14 '16 at 15:59
  • huh? you have no idea what is going on do you. If you set it to true, then of course it will not be detected by the SKScene's touchedBegan method, it gets recognized by the SKNode's toucehdBegan method, that is what userInteractionEnabled is for – Knight0fDragon Sep 14 '16 at 16:01
  • 1
    If all your touch code is done on the scene level, then you need to use nodeAtPoint to get the node you are touching, which gets you the deepest node in the tree, not the node of the highest zposition – Knight0fDragon Sep 14 '16 at 16:05
  • LIke i said, ive read and tested to prove that setting the userInteractionEnabled to true makes the immediate touching of that node to NOT be detected. See this answer: http://stackoverflow.com/questions/22292238/does-userinteractionenabled-property-work-correctly-on-spritekit-nodes – AlvinfromDiaspar Sep 14 '16 at 16:13
  • you proved nothing, It IS detected, by the node NOT the scene, which is exactly what that answer said – Knight0fDragon Sep 14 '16 at 16:13
  • Which is why i said it is not detected in the SKScene's touchesBegan. Good grief. – AlvinfromDiaspar Sep 14 '16 at 16:22
  • Like I said, if you plan on the scene handling all of your touch code, then you need to use a method like `nodeAtPoint` (Which I assume you are using) Using this grabs the deepest node in the tree, so if your tree is `scene->n1->n2` it will always grab n2. If you want it to grab n1, then you need to use `nodesAtPoint` which gets you all the nodes as an array, then you just have to order it by zposition – Knight0fDragon Sep 14 '16 at 16:22
  • Ok, this sounds like a viable solution. I'll come back and mark this as an answer if you create one. Thanks – AlvinfromDiaspar Sep 14 '16 at 16:24
  • Odd thing. I reduced the complexity of my scene to just 1 node (userInteractionEnabled = false). In my touchesBegan method it always always showing only 1 touched object, which is always the SKScene itself. – AlvinfromDiaspar Sep 14 '16 at 16:30
  • what are you using? nodesatpoint? are you grabbing the right location? if you are returning 1 object, that means you are returning the scene – Knight0fDragon Sep 14 '16 at 16:31
  • Please see the snippet i added. It is just iterating thru the touches collection. – AlvinfromDiaspar Sep 14 '16 at 16:33
  • and can you show how you add the nodes – Knight0fDragon Sep 14 '16 at 16:33
  • nothing fancy. just scene.addChild(baseNode). The emulator shows the node displayed just as i expect them to be. – AlvinfromDiaspar Sep 14 '16 at 16:35
  • I want to see how you are creating and adding, the whole method – Knight0fDragon Sep 14 '16 at 16:36
  • I just changed something out of desperation. I made progress. The nodes are now detected! I set the scene's .scaleMode = SKSceneScaleMode.ResizeFill – AlvinfromDiaspar Sep 14 '16 at 16:38
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/123371/discussion-between-knight0fdragon-and-alvinfromdiaspar). – Knight0fDragon Sep 14 '16 at 16:38
  • that shouldnt be the problem – Knight0fDragon Sep 14 '16 at 16:38
  • Well, if i set the fill mode to be anything other than ResizeFill, the detection is always on the Scene. Very strange indeed. – AlvinfromDiaspar Sep 14 '16 at 16:39
  • then we need to figure out what you are doing wrong, because resize fill is most likely what you do not want. – Knight0fDragon Sep 14 '16 at 16:40
  • 2
    oh I see your problem `let sceneTouchPoint = self.convertPointToView(touchLocation)` delete that, `touchLocation` IS your `sceneTouchPoint` – Knight0fDragon Sep 14 '16 at 16:41
  • Not sure if this will solve the problem. Because with the other scale modes, the touches collection doesnt includes the Nodes in the first place. So i know it has nothing to do with these conversions. – AlvinfromDiaspar Sep 14 '16 at 16:45
  • I know because im also printing out the touches.count (which is always 1 for the other scale modes). – AlvinfromDiaspar Sep 14 '16 at 16:46
  • absolutely it does, you should not be using view coordinates on your scene – Knight0fDragon Sep 14 '16 at 16:46
  • before i even being converting touched objects, i need to have a list of touched objects int he first place, right? How can i convert a Node's coordinates if the Node is not even detected as being touched? – AlvinfromDiaspar Sep 14 '16 at 16:49
  • Using hypotheticals here, your scene is 100x100 your view is 300x300, when you are touching the scene at 100x100, you are getting 300x300 which is wrong on every scale mode besides resize, because resize resizes the scene to the view, which like I said, more likely than no you do not want to be using – Knight0fDragon Sep 14 '16 at 16:49
  • 1
    no, how it works is you touch the scene first, you get a scene coordinate, then you ask the scene what nodes are at this scene coordinate, then you process your code based on whatever method you want to use to determine the node touched – Knight0fDragon Sep 14 '16 at 16:50
  • Ah, that makes makes. So basically i shouldnt be concerned with trying to obtain a Node object form this touches collection?! – AlvinfromDiaspar Sep 14 '16 at 16:52
  • 1
    the touch collection is how many fingers is touching the scene – Knight0fDragon Sep 14 '16 at 16:53
  • WTF. i was barking up the wrong tree – AlvinfromDiaspar Sep 14 '16 at 16:54
  • Thanks so much. Please provide an answer and i'll give you credit where it's due! – AlvinfromDiaspar Sep 14 '16 at 16:56

2 Answers2

0

I had several layers of nodes because I used a mask over my game with buttons to make selections and move forward. I had issues with the buttons not working until I made a "startState:Bool = true" and updated this to false when the start screen was clicked through. I then had each of my buttons on that start page to have && startState==true for there clicks to be taken. It may be that your clicks are being recorded - but its not the node you think you are using. I would put print("NodeXXX") on each entry in touches and give it a unique name so you can see where the touches are actually happening.

Hope that helps.

Best regards, mpe

0

I had a similar issue (background in z: 999 + spawning "ducks" nodes in z: <999) that I solved with the following code in Swift 4:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch:UITouch = touches.first!
    let positionInScene = touch.location(in: self)
    let touchedNodes = self.nodes(at: positionInScene)
    for touch in touchedNodes {
        let touchName = touch.name
        if (touchName != nil && touchName!.hasPrefix("pato_")) {
            touch.removeFromParent()
        }
    }
}
Joel Mata
  • 456
  • 4
  • 8