Search code examples
iossprite-kitskspritenodegame-developmentskscene

Allow touch propagation in SpriteKit


Given a SpriteKit scene s, and one node a of type T that inherits from SKSpriteNode contained within s, if both s and a override any touch handler, the touch event is called exclusively on what seems to be the top-most (highest zPosition) node.

If I wanted the scene and its node to perform two different actions concurrently, what pattern would be best to use?

In this case, would it be better to:

  • Let the scene handle all the touches by retrieving the nodes at the location the touch occurred?
  • Have a Touchable protocol that the scene would implement and have any node send up an identifier to the scene through an hypothetical touched(_ nodeID: Int) method?
  • Have all the children nodes refer to a static TouchHandler object that will perform both actions?

What would you suggest anything else?

Update:

Given the following code:

class Parent: SKScene {
    override func didMove(to view: SKView) {
        self.addChild(Foo())
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        //  React to touch, and, for example, move the scene around
    }
}

class Foo: SKSpriteNode {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        //  React to touch, and, for example, scale up the node by 60%
    }
}

If the user taps on the Foo node, showing on screen, only its touchesBegan(_, event:) method gets called - the Parent's method gets ignored.

What pattern would be best to use in order to be able for both objects to react to the touchesBegan(_, event:) callback simultaneously?


Solution

  • I like to handle as much of the code in the object class as possible. So I would handle any of the object touch code inside of it's class file and send the touch back to the scene to be handle separately by the scene.

    class Cat: SKSpriteNode {
    
        var isEnabled = true
        var sendTouchesToScene = true
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent!) {
    
             guard isEnabled else { return }
    
             //send touch to scene
             if sendTouchesToScene {
                 super.touchesBegan(touches, with event)
             }
    
             //handle touches for cat
        }
    }