iosswiftsprite-kitsktilemapnode

Higher column and row index than number of column and row in SKTileMapNode


I want to create a scene where I have buttons to move a cursor from tile to tile inside a SKTileMapNode. I created a 10x8 SKTileMapNode in an extern .sks file in the Spritekit Scene Editor. To set the cursors position exactly on the same as a tile, i wanted to register the specific column and row index of the tile and then find out his position. Using the functions numberOfColumns and tileRowIndex give me higher values than numberOfRows and tileRowIndex, which are 10 and 8. As a result of this Problem my cursor is being displayed on a wrong position. It isn't even even aligned on any tiles position.

class Spielfeld: SKScene {

    var x: Int = 0     // Anzahl Felder in x-Richtung
    var y: Int = 0     // Anzahl Felder in y-Richtung
    var tilemap: SKTileMapNode = SKTileMapNode()
    var up: SKSpriteNode = SKSpriteNode()
    var down: SKSpriteNode = SKSpriteNode()
    var left: SKSpriteNode = SKSpriteNode()
    var right: SKSpriteNode = SKSpriteNode()
    var cursor: SKSpriteNode = SKSpriteNode(imageNamed: "Cursor1Blue")

    override func sceneDidLoad() {
        up = self.childNode(withName: "Up") as! SKSpriteNode
        down = self.childNode(withName: "Down") as! SKSpriteNode
        left = self.childNode(withName: "Left") as! SKSpriteNode
        right = self.childNode(withName: "Right") as! SKSpriteNode

        tilemap = self.childNode(withName: "Tile Map Node") as! SKTileMapNode
        cursor.position = tilemap.centerOfTile(atColumn: 5, row: 5)
        cursor.zPosition = 0.1
        self.addChild(cursor)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch:UITouch = touches.first! as UITouch
        let positionInScene = touch.location(in: self)
        let touchedNode = self.atPoint(positionInScene)
        print(touchedNode.name!)
        if(touchedNode.name == "Tile Map Node") {
            let map = touchedNode as! (SKTileMapNode)
            print(map.tileColumnIndex(fromPosition: positionInScene))   // higher than 10
            print(map.tileRowIndex(fromPosition: positionInScene))      // higher than 8
            print(map.numberOfColumns)  // 10
            print(map.numberOfRows)     // 8
            print(map)
        }
    }
}

Solution

  • When getting the index with tileColumnIndex/tileRowIndex you need to check against the position within the tile map. In your example you give the position for the scene, which might not be the same, depending on where the tile map is positioned.

    If you use the touched location in the map, you should get the correct indexes returned.

    let positionInMap = touch.location(in: map)
    let column = map.tileColumnIndex(fromPosition: positionInMap)
    let row = map.tileRowIndex(fromPosition: positionInMap)
    

    An updated version of touchesBegan() from your example

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch:UITouch = touches.first! as UITouch
        let positionInScene = touch.location(in: self)
        let touchedNode = self.atPoint(positionInScene)
        if(touchedNode.name == "Tile Map Node") {
            let map = touchedNode as! (SKTileMapNode)
            let positionInMap = touch.location(in: map) // Get the touched position in map
            print(map.tileColumnIndex(fromPosition: positionInMap))
            print(map.tileRowIndex(fromPosition: positionInMap))
            print(map.numberOfColumns)
            print(map.numberOfRows)
            print(map)
        }
    }
    

    To ensure that your cursor gets aligned with the tiles when using centerOfTile to position it, add it as a child to the tile map to ensure they are on the same coordinate system. Else you'll have to add the necessary offsets to the cursor position.

    tilemap.addChild(cursor)