以编程方式创建 SpriteKit SKTileMap 的正确方法是什么?
What is the proper way to programmatically create a SpriteKit SKTileMap?
我正在为我正在开发的 iOS 游戏创建瓦片地图。该地图是一个岛屿的俯视图。大多数瓷砖是水,但有些是土地。水砖被重复用于创造水,但 none 的地砖被使用了不止一次,因为所有的地砖都是独一无二的。我查看了 SKTileDefinition、SKTileGroup、SKTileGroupRule、SKTileSet 和 SKTileMap 的文档,这就是我想出的:
func createTileMap() {
let waterTile = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-1"))
let waterTileGroup = SKTileGroup(tileDefinition: waterTile)
let landTile64 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-64"))
let landTile63 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-63"))
let landTile56 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-56"))
let landTile55 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-55"))
let landTile54 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-54"))
let landTile53 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-53"))
let landTile48 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-48"))
let landTile47 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-47"))
let landTile46 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-46"))
let landTile45 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-45"))
let landTile44 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-44"))
let landTile43 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-43"))
let landTile40 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-40"))
let landTile39 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-39"))
let landTile37 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-37"))
let landTile36 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-36"))
let landTile35 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-35"))
let landTile34 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-34"))
let landTile31 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-31"))
let landTile30 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-30"))
let landTile27 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-27"))
let landTile26 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-26"))
let landTile25 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-25"))
let landTile23 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-23"))
let landTile22 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-22"))
let landTile21 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-21"))
let landTile20 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-20"))
let landTile18 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-18"))
let landTile17 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-17"))
let landTile13 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-13"))
let landTile12 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-12"))
let landTile11 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-11"))
let landTile3 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-3"))
let landTileGroupRule = SKTileGroupRule(adjacency: .adjacencyAll, tileDefinitions: [landTile64, landTile63, landTile56, landTile55, landTile54, landTile53, landTile48, landTile47, landTile46, landTile45, landTile44, landTile43, landTile40, landTile39, landTile37, landTile36, landTile35, landTile34, landTile31, landTile30, landTile27, landTile26, landTile25, landTile23, landTile22, landTile21, landTile20, landTile18, landTile17, landTile13, landTile12, landTile11, landTile3])
let landTileGroup = SKTileGroup(rules: [landTileGroupRule])
let tileSet = SKTileSet(tileGroups: [waterTileGroup, landTileGroup], tileSetType: .grid)
tileMap = SKTileMapNode(tileSet: tileSet, columns: 8, rows: 8, tileSize: waterTile.size)
tileMap.fill(with: waterTileGroup)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile64, forColumn: 7, row: 0)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile63, forColumn: 6, row: 0)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile56, forColumn: 7, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile55, forColumn: 6, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile54, forColumn: 5, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile53, forColumn: 4, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile48, forColumn: 7, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile47, forColumn: 6, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile46, forColumn: 5, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile45, forColumn: 4, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile44, forColumn: 3, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile43, forColumn: 2, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile40, forColumn: 7, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile39, forColumn: 6, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile37, forColumn: 4, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile36, forColumn: 3, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile35, forColumn: 2, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile34, forColumn: 1, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile31, forColumn: 6, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile30, forColumn: 5, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile27, forColumn: 2, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile26, forColumn: 1, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile25, forColumn: 0, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile23, forColumn: 6, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile22, forColumn: 5, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile21, forColumn: 4, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile20, forColumn: 3, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile18, forColumn: 1, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile17, forColumn: 0, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile13, forColumn: 4, row: 6)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile12, forColumn: 3, row: 6)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile11, forColumn: 2, row: 6)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile3, forColumn: 2, row: 7)
self.addChild(tileMap)
}
现在,这是非常粗糙的代码,但我不确定我可以从这里走向何方。我正在加载每个地块,然后明确告诉它应该进入哪一列和哪一行。任何没有明确布局的地块都是水地块。我想避免为此使用任何 Xcode 的 GUI 工具,并完全以编程方式创建地图。这段代码有效,而且它提高了性能(我最初只是滚动整个地图图像,而不是使用图块),它非常丑陋并且尖叫 "There must be a more concise way of doing this!"。我在这里错过了什么?
一种方法是在文本文件中定义地图布局,其中的列和行指定要放置在特定位置的图块。这样就可以为每个游戏级别指定不同的地图,同时仍然使用相同的场景。此示例假设只有一个 SKTileSet
并且不需要填充背景。
// Level1.txt
01 01 01 01 01 01 63 64
01 01 01 01 53 54 55 56
01 01 43 44 45 46 47 48
01 34 35 36 37 01 39 40
25 26 27 01 01 30 31 01
17 18 01 20 21 22 23 01
01 01 11 12 13 01 01 01
01 01 03 01 01 01 01 01
遍历每一列和每一行,检索指定的图块并调用 setTileGroup
。
let path = Bundle.main.path(forResource: "Level1.txt", ofType: nil)
do {
let fileContents = try String(contentsOfFile:path!, encoding: String.Encoding.utf8)
let lines = fileContents.components(separatedBy: "\n")
for row in 0..<lines.count {
let items = lines[row].components(separatedBy: " ")
for column in 0..<items.count {
let tile = tileMap.tileSet.tileGroups.first(where: {[=11=].name == "map-tile-" + items[column]})
tileMap.setTileGroup(tile, forColumn: column, row: row)
}
}
} catch {
print("Error loading map")
}
这消除了示例中的第二个代码块。如果您想在使用 Xcode GUI 工具方面做出一些妥协,那么可以通过将 SKTileGroup
创建为 sks
文件来消除第一段代码。
不过,我建议在使用 SKTileMapNode
时使用 GUI 工具,因为它们提供了很多功能。
我正在为我正在开发的 iOS 游戏创建瓦片地图。该地图是一个岛屿的俯视图。大多数瓷砖是水,但有些是土地。水砖被重复用于创造水,但 none 的地砖被使用了不止一次,因为所有的地砖都是独一无二的。我查看了 SKTileDefinition、SKTileGroup、SKTileGroupRule、SKTileSet 和 SKTileMap 的文档,这就是我想出的:
func createTileMap() {
let waterTile = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-1"))
let waterTileGroup = SKTileGroup(tileDefinition: waterTile)
let landTile64 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-64"))
let landTile63 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-63"))
let landTile56 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-56"))
let landTile55 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-55"))
let landTile54 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-54"))
let landTile53 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-53"))
let landTile48 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-48"))
let landTile47 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-47"))
let landTile46 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-46"))
let landTile45 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-45"))
let landTile44 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-44"))
let landTile43 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-43"))
let landTile40 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-40"))
let landTile39 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-39"))
let landTile37 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-37"))
let landTile36 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-36"))
let landTile35 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-35"))
let landTile34 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-34"))
let landTile31 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-31"))
let landTile30 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-30"))
let landTile27 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-27"))
let landTile26 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-26"))
let landTile25 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-25"))
let landTile23 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-23"))
let landTile22 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-22"))
let landTile21 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-21"))
let landTile20 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-20"))
let landTile18 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-18"))
let landTile17 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-17"))
let landTile13 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-13"))
let landTile12 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-12"))
let landTile11 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-11"))
let landTile3 = SKTileDefinition(texture: SKTexture(imageNamed: "map-tile-3"))
let landTileGroupRule = SKTileGroupRule(adjacency: .adjacencyAll, tileDefinitions: [landTile64, landTile63, landTile56, landTile55, landTile54, landTile53, landTile48, landTile47, landTile46, landTile45, landTile44, landTile43, landTile40, landTile39, landTile37, landTile36, landTile35, landTile34, landTile31, landTile30, landTile27, landTile26, landTile25, landTile23, landTile22, landTile21, landTile20, landTile18, landTile17, landTile13, landTile12, landTile11, landTile3])
let landTileGroup = SKTileGroup(rules: [landTileGroupRule])
let tileSet = SKTileSet(tileGroups: [waterTileGroup, landTileGroup], tileSetType: .grid)
tileMap = SKTileMapNode(tileSet: tileSet, columns: 8, rows: 8, tileSize: waterTile.size)
tileMap.fill(with: waterTileGroup)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile64, forColumn: 7, row: 0)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile63, forColumn: 6, row: 0)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile56, forColumn: 7, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile55, forColumn: 6, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile54, forColumn: 5, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile53, forColumn: 4, row: 1)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile48, forColumn: 7, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile47, forColumn: 6, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile46, forColumn: 5, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile45, forColumn: 4, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile44, forColumn: 3, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile43, forColumn: 2, row: 2)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile40, forColumn: 7, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile39, forColumn: 6, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile37, forColumn: 4, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile36, forColumn: 3, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile35, forColumn: 2, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile34, forColumn: 1, row: 3)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile31, forColumn: 6, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile30, forColumn: 5, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile27, forColumn: 2, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile26, forColumn: 1, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile25, forColumn: 0, row: 4)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile23, forColumn: 6, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile22, forColumn: 5, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile21, forColumn: 4, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile20, forColumn: 3, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile18, forColumn: 1, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile17, forColumn: 0, row: 5)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile13, forColumn: 4, row: 6)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile12, forColumn: 3, row: 6)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile11, forColumn: 2, row: 6)
tileMap.setTileGroup(landTileGroup, andTileDefinition: landTile3, forColumn: 2, row: 7)
self.addChild(tileMap)
}
现在,这是非常粗糙的代码,但我不确定我可以从这里走向何方。我正在加载每个地块,然后明确告诉它应该进入哪一列和哪一行。任何没有明确布局的地块都是水地块。我想避免为此使用任何 Xcode 的 GUI 工具,并完全以编程方式创建地图。这段代码有效,而且它提高了性能(我最初只是滚动整个地图图像,而不是使用图块),它非常丑陋并且尖叫 "There must be a more concise way of doing this!"。我在这里错过了什么?
一种方法是在文本文件中定义地图布局,其中的列和行指定要放置在特定位置的图块。这样就可以为每个游戏级别指定不同的地图,同时仍然使用相同的场景。此示例假设只有一个 SKTileSet
并且不需要填充背景。
// Level1.txt
01 01 01 01 01 01 63 64
01 01 01 01 53 54 55 56
01 01 43 44 45 46 47 48
01 34 35 36 37 01 39 40
25 26 27 01 01 30 31 01
17 18 01 20 21 22 23 01
01 01 11 12 13 01 01 01
01 01 03 01 01 01 01 01
遍历每一列和每一行,检索指定的图块并调用 setTileGroup
。
let path = Bundle.main.path(forResource: "Level1.txt", ofType: nil)
do {
let fileContents = try String(contentsOfFile:path!, encoding: String.Encoding.utf8)
let lines = fileContents.components(separatedBy: "\n")
for row in 0..<lines.count {
let items = lines[row].components(separatedBy: " ")
for column in 0..<items.count {
let tile = tileMap.tileSet.tileGroups.first(where: {[=11=].name == "map-tile-" + items[column]})
tileMap.setTileGroup(tile, forColumn: column, row: row)
}
}
} catch {
print("Error loading map")
}
这消除了示例中的第二个代码块。如果您想在使用 Xcode GUI 工具方面做出一些妥协,那么可以通过将 SKTileGroup
创建为 sks
文件来消除第一段代码。
不过,我建议在使用 SKTileMapNode
时使用 GUI 工具,因为它们提供了很多功能。