以编程方式创建SpriteKit SKTileMap的正确方法是什么? [英] What is the proper way to programmatically create a SpriteKit SKTileMap?

查看:202
本文介绍了以编程方式创建SpriteKit SKTileMap的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我正在制作的iOS游戏创建一个平铺地图。地图是岛屿的俯视图。大多数瓷砖都是水,但有些是土地。水瓦被重新用于创造水,但是没有一块地砖被使用不止一次,因为所有的地砖都是独一无二的。我查看了SKTileDefinition,SKTileGroup,SKTileGroupRule,SKTileSet和SKTileMap的文档,这就是我想出的:

I am creating a tile map for an iOS game I am working on. The map is a top down view of an island. Most of the tiles are water, but some are land. The water tile is reused to create the water, but none of the land tiles are used more than once, because all of the land tiles are unique. I have looked through the docs for SKTileDefinition, SKTileGroup, SKTileGroupRule, SKTileSet, and SKTileMap, and this is what I came up with:

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工具,并完全以编程方式创建地图。这段代码有效,并且它提高了性能(我最初只是在整个地图图像上滚动,而不是使用图块),它只是非常难看并尖叫必须有一个更简洁的方法来做到这一点!。我在这里缺少什么?

Now, this is pretty gross code, but I am not sure where I can go from here. I am loading each land tile, and then explicitly telling it which column and row it should go in. Any tiles that are not explicitly laid out are water tiles. I would like to avoid using any of Xcode's GUI tools for this, and create the map entirely programmatically. This code works, and it improved performance (I was initially just scrolling over the entire map image, not using tiles), it's just very ugly and screams "There must be a more concise way of doing this!". What am I missing here?

推荐答案

一种方法是在文本文件中定义地图布局,其中列和行指定哪个瓷砖放置在特定位置。然后,可以为每个游戏关卡指定不同的地图,同时仍然使用相同的场景。此示例假设只有一个 SKTileSet ,并且不需要填充背景。

One approach is to define the map layout in a text file with columns and rows that specify which tile to place at specific locations. Then it will be possible to specify a different map for each game level, while still using the same scene. This example assumes there is only one SKTileSet and flood filling the background is not required.

// 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

Iterate over each column and row, retrieve the specified tile and call 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: {$0.name == "map-tile-" + items[column]})
            tileMap.setTileGroup(tile, forColumn: column, row: row)
        }
    }
} catch {
    print("Error loading map")
}

这消除了示例中的第二个代码块。如果你想在使用Xcode GUI Tools时有所妥协,那么可以通过创建 SKTileGroup 作为 sks来消除第一个代码块 file。

This eliminates the second block of code in your example. If you want to compromise a bit on using Xcode GUI Tools, then the first block of code could be eliminated by creating the SKTileGroup as an sks file.

我建议在使用 SKTileMapNode 时使用GUI工具,因为他们提供了很多功能。

I would recommend using the GUI Tools when working with SKTileMapNode though, since they provide a lot of functionality.

这篇关于以编程方式创建SpriteKit SKTileMap的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆