iossprite-kittouchsktilemapnode

SKTileMapNode: detecting touched Tile?


Imagine a game world that's nothing other than an SKTileMapNode with 10x10 tiles on the screen.

The user touches a tile.

Does SKTileMapNode provide a way to know which tile has been touched? Or do coordinate hunts need be done to determine which tile is in the location of the touch?

Or is there some other way that this should be done?


Solution

  • Using a UITapGestureRecognizer you can retrieve the touched tile using the tileDefinition function from SKTileMapNode.

    func handleTapFrom(recognizer: UITapGestureRecognizer) {
        if recognizer.state != .ended {
            return
        }
    
        let recognizorLocation = recognizer.location(in: recognizer.view!)
        let location = self.convertPoint(fromView: recognizorLocation)
    
        guard let map = childNode(withName: "background") as? SKTileMapNode else {
            fatalError("Background node not loaded")
        }
    
        let column = map.tileColumnIndex(fromPosition: location)
        let row = map.tileRowIndex(fromPosition: location)
        let tile = map.tileDefinition(atColumn: column, row: row)
    }
    

    Then if you have added userData in the TilemapEditor, this can be retrieved. Values to include in userData might be cost to move through the tile etc.

    let data = tile.userData?.value(forKey: "myKey")
    

    The advantage of using Recognizers is that Tap, Pan and Long Press can be handled cleanly in separate functions that don't interfere with each other. You initialise the gesture recognizor in SKScene.

    override func didMove(to view: SKView) {
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTapFrom(recognizer:)))
        tapGestureRecognizer.numberOfTapsRequired = 1
        view.addGestureRecognizer(tapGestureRecognizer)
    }