I am in the process of building a fairly complex game in SpriteKit. Per Apple’s documentation (see Apple Developer Documentation) there are two main ways of handling events in a SpriteKit game.
One is to handle all user interaction from a single node, the main SKScene in my case. I attach gesture recognizers in the SKScene.didMove(to:) method and test for which nodes were interacted with, then trigger the appropriate event based on the node. This is the technique I am currently using because it seems to be what everyone recommends, based on online research.
The second approach involves attaching gesture recognizers on a node-by-node basis.
I am quickly running into a scale problem of handling all the events at the SKScene level (the first approach). Currently I am checking which nodes were touched using the name of the node, then triggering the appropriate event based on the touched node. This worked fine when I had around a dozen different nodes the user could interact with, but it is quickly getting out of control as I build out my game and add dozens and dozens of different nodes that are capable of being interacted with. This technique does not seem scalable at all.
I would like to start exploring attaching gesture recognizers to the individual nodes, but I cannot find a single example anywhere online of this technique. I have also purchased and read a book on SpriteKit, which only describes the former technique. Can anyone point me in the right direction, provide some code examples, or tell me where I might find information about how to better scale out a SpriteKit game, specifically in terms of event handling?
You can’t add gesture recognizers to SpriteKit nodes. You can add them only to views. That’s why every example you see adds gesture recognizers to SpriteKit scenes and not nodes.
If you want individual nodes to respond to player input, create a SKNode subclass and override the touch input methods, such as touchesMoved.
Hey thank you so much for the response and info. Your comments were incredibly helpful.
Even though I was vaguely aware of what you are saying (Apple clearly states that SKNode inherits from UIResponder so that you can override the pertinent touches methods), somehow it felt like I would be doing something wrong by using this methodology, because I was not able to find anyone (books, forums, online tutorials, etc) suggesting that this is how you should handle your user input events in a SpriteKit game.
I am in the process of implementing the touches methods for one of my SKNodes and will see if I can get it to work. I am running into an immediate problem that I have a SKTileMapNode that sits over top of (i.e. zPosition is higher) than some of my SKSpriteNodes that I want to be able to tap, and it appears that SpriteKit will swallow touch events even if the isUserInteractionEnabled = false of the higher node. Can you confirm that fact?
Even if you create a SKNode subclass and override the touch methods, they will not fire if the node sits underneath another node? That appears to be what is happening (my touchesBegan is not firing in the SKNode subclass), but I’m not sure if this is due to the zPosition issue, or something else entirely.
I have not used SpriteKit’s tile nodes or done what you’re trying to do so I don’t have a definite answer. It wouldn’t surprise me that if another node was on top of the node you wanted to touch that it would prevent the touch event from firing. You can test the hypothesis by temporarily putting the sprite over the tile map and seeing if the touch event registers.
Good idea, thanks. I just tried it and sure enough, when I set the zPosition of my SKNode subclass to be higher than the (currently not filled with tiles and therefore transparent) SKTileMapNode, the touchesBegan does indeed fire in the SKNode subclass. But that is a separate issue that I’ll have to think through and potentially modify how I am adding my nodes. Thanks so much, you were an immense help.