Пользовательская группа в наборе TileMap не выбирает правильную плитку - PullRequest
0 голосов
/ 06 сентября 2018

Я создал собственную группу со всеми возможными комбинациями окружающих плиток.

Custom group screenshot

Я использую его с включенным режимом автоматического сопоставления на моей TileMap, и вот результат:

Render in the editor

Как видите, есть несколько ошибок:

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

Я пробовал это как программно, так и в редакторе. Поведение такое же.

Моя мысль состоит в том, что движок автоматического картирования берет первый соответствующий элемент при работе с углами (вверху слева, внизу справа). Вот некоторые из ошибок, связанных с элементом, который должен иметь движок:

Annotated tiles

Все неправильные находятся перед соответствующей плиткой. Но я не смог найти способ переупорядочить листы для проверки этой теории (в редакторе или даже в файле конфигурации, так как группа находится в двоичном файле).

Есть ли способ решить эту проблему?

Заранее спасибо за ваше время.

EDIT

Я попытался удалить и воссоздать некоторые неправильные тайлы, и это подтверждает теорию: когда речь идет об углах, механизм автоматического выбора берет первый соответствующий элемент, даже если в них деактивированы углы. Он не заботится о том, чтобы проверить, есть ли лучший тайл, соответствующий правилу угла.

Вопрос остается прежним: есть ли способ исправить это поведение, или я должен кодировать механизм автоматического определения?

1 Ответ

0 голосов
/ 16 октября 2018

Я работаю над этим уже 2 недели. У меня были серьезные проблемы с автоматическим тайлингом SpriteKit SKTileMapNode. Я следовал этой статье и выяснил, что мне нужно сделать, чтобы получить правильный автоматический тайлинг. Я просматривал весь интернет, копаясь в старых форумах и сайтах, пытаясь собрать воедино то, что объясняла статья.

Наконец, после нескольких недель тестирования и бесчисленных проб / ошибок, я создал функциональный фрагмент кода, который имитирует то, что автоматическое разбиение на листы должно делать в 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 битовых масок для возможных ориентаций тайлов. Он берет возвращенную битовую маску и сравнивает ее с этим массивом, чтобы найти индекс, в котором она находится. Затем он обращается к массиву групп плиток и устанавливает плитку во вторую карту плиток на основе индекса массива битовых масок.

Надеюсь, это имело смысл.

Вот лист листов спрайта, в котором каждая плитка организована слева направо и от наименьшего к наибольшему.

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

...