8

does anyone know how to create an SKTileMapNode programmatically using Swift please? (NOTE: I do not want to do this using the editor, I want to achieve this programmatically only)

I have tried the following but does not render my tile map

let bgTexture = SKTexture(imageNamed: "background")
let bgDefinition = SKTileDefinition(texture: bgTexture, size: bgTexture.size())
let bgGroup = SKTileGroup(tileDefinition: bgDefinition)
let tileSet = SKTileSet(tileGroups: [bgGroup])
let bgNode = SKTileMapNode(tileSet: tileSet, columns: 5, rows: 5, tileSize: bgTexture.size())
bgNode.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2)
bgNode.setScale(1)
self.addChild(bgNode)

Any help greatly appreciated

Neil Stevens
  • 3,534
  • 6
  • 42
  • 71
  • 1
    you never actually make your map, how does it know what tiles you are using, The node knows the tiles, and you create the space for the map, you need to actually make the map now, I do not know too much about this so I can't provide an answer for you. – Knight0fDragon Sep 16 '16 at 17:49
  • @Knight0fDragon do you happen to know if a SKTileMapNode can be scaled? – Confused Sep 19 '16 at 17:59
  • @Confused, I wouldn't see why not, scale is a member of SKNode (well xScale yScale is) – Knight0fDragon Sep 19 '16 at 18:02
  • 1
    Yeah... I'm just not convinced anything or SceneKit or SpriteKit ever works as advertised... colour me skeptical, and confused ;) – Confused Sep 19 '16 at 18:03
  • More gotchas than a Palin interview. – Confused Sep 19 '16 at 18:03
  • 1
    @Confused You can apply scaling to the `SKCameraNode` to e.g. adjust size for different devices and orientations. – Mark Brownsword Sep 24 '16 at 05:25

2 Answers2

7

To layout the entire map with the single background tile you would iterate through each column and each row. You'll need to retrieve the background tile first.

let tile = bgNode.tileSet.tileGroups.first(
    where: {$0.name == "background"})

for column in 0..4 {
    for row in 0..4 {
        bgNode.setTileGroup(tile, forColumn: column, row: row)
    }
}

There is also a convenience function to achieve a flood fill;

bgNode.fill(with: tile)

There is also an initialiser for SKTilemapNode that accepts SKTileGroup

let bgNode = SKTileMapNode(tileSet: tileSet, columns: 5, rows: 5, tileSize: bgTexture.size(), fillWithTileGroup: tile)

I strongly recommend to leverage the functionality built into Xcode for creating TileSets and TileMaps. You can still programatically fill the map.

Mark Brownsword
  • 2,287
  • 2
  • 14
  • 23
6

In case it's helpful to anyone, here's the whole thing put together:

class MyGameScene: SKScene {
    override func didMove(to view: SKView) {
        guard let tileSet = SKTileSet(named: "testset") else {
            // hint: don't use the filename for named, use the tileset inside
            fatalError()
        }

        let tileSize = tileSet.defaultTileSize // from image size
        let tileMap = SKTileMapNode(tileSet: tileSet, columns: 5, rows: 5, tileSize: tileSize)
        let tileGroup = tileSet.tileGroups.first
        tileMap.fill(with: tileGroup) // fill or set by column/row
        //tileMap.setTileGroup(tileGroup, forColumn: 5, row: 5)
        self.addChild(tileMap)
    }
}
zekel
  • 9,227
  • 10
  • 65
  • 96