2

I'm trying to temporarily disable touch on the entire screen, despite their being many sprites with touchesBegun onscreen.

I thought, obviously wrongly, turning off touch for the scene would do it:

    scene?.isUserInteractionEnabled = false

But that didn't work, so I tried this, which also didn't work:

    view?.scene?.isUserInteractionEnabled = false

That also didn't work, so I tried this, also from inside the scene:

    self.isUserInteractionEnabled = false
Confused
  • 6,048
  • 6
  • 34
  • 75
  • I have the same problem. Unlike in UIKit, in SpriteKit disabling user interaction for parent node doesn't disables it's children. The same is when you disable the scene view. – kelin Apr 14 '21 at 11:43

2 Answers2

4

There is no global method to turn off the touch, whatever is at the top of the drawing queue is the first responder.

You need to iterate through all of your nodes from your scene and turn them off:

enumerateChildNodesWithName("//*", usingBlock: 
    { (node, stop) -> Void in  
       node.isUserInteractionEnabled = false
    })

Now the problem is turning them back on, if you use this method, you will turn it on for everything, so you may want to adopt a naming convention for all your touchable sprites

enumerateChildNodesWithName("//touchable", usingBlock: 
    { (node, stop) -> Void in  
       node.isUserInteractionEnabled = true
    })

This will look for any node that has a name that begins with touchable.

This method involves recursion, so if you have a ton of nodes, it can be slow. Instead you should use an alternative method:

let disableTouchNode = SKSpriteNode(color:SKColor(red:0.0,green:0.0,blue:0.0,alpha:0.1),size:self.size)
disableTouchNode.isUserinteractionEnabled = true
disableTouchNode.zPosition = 99999
self.addChild(disableTouchNode)

What this does is slap on an almost transparent node on top of all elements the size of the scene. This way when a user touches the screen, this node will absorb it instead of anything else.

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Ouch. And Yuk. Plus THANK YOU! I've decided to put the objects I want to turn off into an array, flip them to interactionoff, and then back on when I need them again. Baffling that there's not a neater way to temporarily turn off all input. – Confused Nov 16 '16 at 19:52
  • And nice trick, the "layer" at 99999 to grab and swallow touches! – Confused Nov 16 '16 at 19:53
  • I'm now using this enumerate thing to remove one particular node... the timer bar from the other question... can you explain what `(node, stop)` is doing? – Confused Nov 16 '16 at 22:55
  • 1
    node is the current node in your list that is being evaluated, you use stop to stop the enumerating search when you found the node you were looking for. https://developer.apple.com/reference/spritekit/sknode/1483024-enumeratechildnodes – Knight0fDragon Nov 16 '16 at 22:58
  • THAT IS SENSATIONAL. I had no idea it was possible to stop an enumerate test/check/search on find. That's ideal. THANK YOU!!! Works like a charm!!! `scene?.enumerateChildNodes(withName: "timerBar", using: { (node, stop) in node.removeFromParent()})` – Confused Nov 16 '16 at 22:59
  • @Knight0fDragon could you please take a look at this question for me http://stackoverflow.com/questions/43072572/how-can-i-make-my-level-menu-scrollable-vertically. Thanks – ItsMeAgain Apr 05 '17 at 21:04
  • To identify "touchable" nodes you can introduce formal protocol `Touchable`, for example and inherit the specific nodes from it. Then, during the enumeration, check if node `is Touchable`. You also can add a flag for this purpose. Usually we have some nodes that should never be touchable. – kelin Apr 14 '21 at 11:46
1

The following will disable all touches

self.view?.isUserInteractionEnabled = false
0x141E
  • 12,613
  • 2
  • 41
  • 54