TileMap集中的自定义组未选择适当的图块

时间:2018-09-06 07:11:29

标签: ios xcode sprite-kit sktilemapnode

我将周围瓷砖的每种可能组合组成了一个自定义小组。

Custom group screenshot

我在TileMap上启用了自动映射模式的情况下使用它,结果如下:

Render in the editor

如您所见,有几个错误:

Annotated render (green = proper tile, red = wrong tile)

我在编程和编辑器中都尝试过。行为是相同的。

我的想法是,当处理拐角时(左上,右下),自动映射引擎会采用第一个匹配元素。以下是一些错误,这些错误与引擎应该具有的元素有关:

Annotated tiles

所有错误的一个都在匹配图块之前。但是我找不到任何方法来重新排列图块以测试该理论(在编辑器中,甚至在配置文件中,因为该组在二进制文件中)。

有什么办法可以解决这个问题?

提前感谢您的时间。

编辑

我试图删除并重新创建一些错误的图块,这证实了这一理论:处理角度时,即使在其中禁用了角,自动映射引擎也会采用第一个匹配元素。它并不会检查是否还有更好的图块匹配角规则。

问题仍然存在:有没有办法纠正这种行为,还是我必须编写自动映射引擎的代码?

1 个答案:

答案 0 :(得分:2)

我已经为此工作了两个星期。 SpriteKit SKTileMapNode自动平铺出现了一些严重问题。我遵循了this article,并弄清楚需要做些什么才能获得正确的自动平铺。我在整个Internet上浏览了旧的论坛和网站,试图拼凑出文章所要解释的内容。

最后,经过数周的测试和无数次的尝试/错误,我想出了一段有效的代码来模拟SpriteKit中自动平铺应该执行的操作。

// Auto-tiling tool to bypass the auto-mapping in SpriteKit.
// This tool opens up a lot more options than the one provided by SpriteKit
class TileData {

    var map:SKTileMapNode
    var column:Int
    var row:Int
    //var array2D = [[Int]]()

    init(Column: Int, Row: Int, Map: SKTileMapNode) {
        column = Column
        row = Row
        map = Map
    }

    func returnTileData(C: Int, R: Int) -> Int {
        var directions = 0
        if map.tileGroup(atColumn: C, row: R) == tileGroups[48] {
            if map.tileGroup(atColumn: C - 1, row: R + 1) == tileGroups[48] {
                directions += 1
            }
            if map.tileGroup(atColumn: C, row: R + 1) == tileGroups[48] {
                directions += 2
            }
            if map.tileGroup(atColumn: C + 1, row: R + 1) == tileGroups[48] {
                directions += 4
            }
            if map.tileGroup(atColumn: C - 1, row: R) == tileGroups[48] {
                directions += 8
            }
            if map.tileGroup(atColumn: C + 1, row: R) == tileGroups[48] {
                directions += 16
            }
            if map.tileGroup(atColumn: C - 1, row: R - 1) == tileGroups[48] {
                directions += 32
            }
            if map.tileGroup(atColumn: C, row: R - 1) == tileGroups[48] {
                directions += 64
            }
            if map.tileGroup(atColumn: C + 1, row: R - 1) == tileGroups[48] {
                directions += 128
            }
        }
        let east = (directions & Dir.East.rawValue) == Dir.East.rawValue
        let west = (directions & Dir.West.rawValue) == Dir.West.rawValue
        let south = (directions & Dir.South.rawValue) == Dir.South.rawValue
        let north = (directions & Dir.North.rawValue) == Dir.North.rawValue
        let northEast = (directions & Dir.NorthEast.rawValue) == Dir.NorthEast.rawValue
        let northWest = (directions & Dir.NorthWest.rawValue) == Dir.NorthWest.rawValue
        let southEast = (directions & Dir.SouthEast.rawValue) == Dir.SouthEast.rawValue
        let southWest = (directions & Dir.SouthWest.rawValue) == Dir.SouthWest.rawValue

        return getTileData(east: east, west: west, north: north, south: south,
                       northWest: northWest, northEast: northEast, southWest:southWest, southEast: southEast)
    }

    func getTileData(east: Bool, west: Bool, north: Bool, south: Bool, northWest: Bool, northEast: Bool, southWest: Bool, southEast: Bool) -> Int {
        var directions = (east ? Dir.East.rawValue : 0) | (west ? Dir.West.rawValue : 0)  | (north ? Dir.North.rawValue : 0) | (south ? Dir.South.rawValue : 0)

        directions |= ((north && west) && northWest) ? Dir.NorthWest.rawValue : 0
        directions |= ((north && east) && northEast) ? Dir.NorthEast.rawValue : 0
        directions |= ((south && west) && southWest) ? Dir.SouthWest.rawValue : 0
        directions |= ((south && east) && southEast) ? Dir.SouthEast.rawValue : 0

        return directions
    }
}

我将尝试确切解释它的作用以及如何使其起作用。

该算法通过在第一张地图中填充数据开始。它采用自定义类,传递列,行和第一个预填充的地图。它检查第一个地图中每个图块的邻居,并根据它返回一个位掩码,然后根据返回的位掩码将一个图块设置到第二个图中。

这是整个过程。当然,它可能会得到改善。但这需要时间。

// There are 47 possible tile orientations.
let tileBits = [2, 8, 10, 11, 16, 18, 22, 24, 26, 27,
                30, 31, 64, 66, 72, 74, 75, 80, 82, 86,
                88, 90, 91, 94, 95, 104, 106, 107, 120,
                122, 123, 126, 127, 208, 210, 214, 216, 218,
                219, 222, 223, 248, 250, 251, 254, 255, 0]

// Because of how buggy SKTileMapNodes currently are, two tile maps are needed for this process

let tileMap = SKTileMapNode(tileSet: tileSet, columns: columns, rows: rows, tileSize: tileSize)
let tileMap2 = SKTileMapNode(tileSet: tileSet, columns: columns, rows: rows, tileSize: tileSize)

for c in 0..<tileMap.numberOfColumns {
    for r in 0..<tileMap.numberOfRows {
        // Fill your first tile map in here. 
        // Pretty standard stuff.
    }
}

for c in 0..<tileMap2.numberOfColumns {
    for r in 0..<tileMap2.numberOfRows {
        // Assign variable to the class and pass in the pre-filled tileMap
        let tile = TileData(Column: c, Row: r, Map: tileMap)

        // Get the bit-mask of the tile at (column, row)
        let number = tile.returnTileData(C: c, R: r)

        // If the array of tileBits contains the bitmask
        if tileBits.contains(number) {
            // Find out where it is at in the array

            guard let bit = tileBits.firstIndex(of: number) else { return }

            // Set the Tile Group
            tileMap2.setTileGroup(tileGroups[bit], forColumn: c, row: r)
        }
    }
}
// tileMap.setScale(0.2)
self.addChild(tileMap2)

有47种可能的图块排列。基本上,您必须创建一个包含48个图块组的数组。 1-47是可能的图块方向。 48代表第一张地图中的填充空间。另一个阵列存储所有47个位掩码,以获取可能的图块方向。它获取返回的位掩码,并将其与该数组进行比较以找到其所在的索引。然后,它访问图块组的数组,并根据位掩码数组的索引将图块设置到第二个图块映射中。

希望这是有道理的。

这是图块Sprite-sheet,每个图块从左到右,从最小到最大排列。

2、8、10、11、16、18、22、24、26、27、30、31、64、66、72、74、75、80、82、86、88、90、91、94 ,95、104、106、107、120、122、123、126、127、208、210、214、216、218、219、222、223、248、250、251、254、255、0

Image 1