Генерация процедурных уровней с помощью Cellular Automaton в Swift

Есть ли простой способ создать процедурный уровень с клеточным автоматом в swift/SpriteKit (библиотека?)? Я хочу создать «пещеру» с 11 полями по высоте и 22 по ширине. Они должны создаваться случайным образом, и каждое поле без стены должно быть достигнуто. Я только что нашел документацию. используя Objective-C, с которым я не знаком. Я трачу довольно много времени, пытаясь понять код и безуспешно следовать примеру.

PS: если есть более простой способ, я ценю некоторые алгоритмы


person Lukas Köhl    schedule 09.11.2015    source источник


Ответы (2)


Я сделал игровую площадку, где можно экспериментировать

//: Playground - noun: a place where people can play

import UIKit
import SpriteKit
import XCPlayground


class Cave {

    var cellmap:[[Bool]]

    let chanceToStartAlive = 35
    let deathLimit = 3
    let birthLimit = 4
    var xCell = 40 // number of cell in x axes
    var yCell = 20 // number of cell in y axes
    var wCell = 20 // cell width
    var hCell = 20 // cell height

    init(){
        cellmap = Array(count:yCell, repeatedValue:
            Array(count:xCell, repeatedValue:false))

        cellmap = self.initialiseMap(xCell, yIndex:yCell)
    }

    func initialiseMap(xIndex:Int, yIndex:Int) -> [[Bool]]{
        var map:[[Bool]] = Array(count:yIndex, repeatedValue:
            Array(count:xIndex, repeatedValue:false))

        for y in 0...(yIndex - 1) {
            for x in 0...(xIndex - 1) {

                let diceRoll = Int(arc4random_uniform(100))

                if diceRoll < chanceToStartAlive {
                    map[y][x] = true
                } else {
                    map[y][x] = false
                }
            }
        }
        return map
    }

    func addSprite(scene:SKScene){
        for (indexY, row) in cellmap.enumerate(){
            for (indexX, isWall) in row.enumerate(){
                if isWall {

                    let wall = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: wCell, height: hCell))
                    wall.position = CGPoint(x: (indexX * wCell) + (wCell / 2) , y: (indexY * hCell) + (hCell / 2)  )
                    scene.addChild(wall)
                }
            }
        }
    }

    func countAliveNeighbours(x:Int, y:Int) -> Int{

        var count = 0
        var neighbour_x = 0
        var neighbour_y = 0

        for i in -1...1 {

            for j in -1...1 {

                neighbour_x = x + j
                neighbour_y = y + i


                if(i == 0 && j == 0){
                } else if(neighbour_x < 0 || neighbour_y < 0 || neighbour_y >= cellmap.count || neighbour_x >= cellmap[0].count){
                    count = count + 1
                } else if(cellmap[neighbour_y][neighbour_x]){
                    count = count + 1
                }

            }

        }

        return count

    }

    func applyRules(){

        var newMap:[[Bool]] = Array(count:yCell, repeatedValue:
            Array(count:xCell, repeatedValue:false))



        for y in 0...(cellmap.count - 1) {
            for x in 0...(cellmap[0].count - 1) {
                let nbs = countAliveNeighbours( x, y: y);
                if(cellmap[y][x]){
                    if(nbs < deathLimit){
                        newMap[y][x] = false;
                    }
                    else{
                        newMap[y][x] = true;
                    }
                } else{
                    if(nbs > birthLimit){
                        newMap[y][x] = true;
                    }
                    else{
                        newMap[y][x] = false;
                    }
                }
            }
        }
        cellmap = newMap
    }
}

let view:SKView = SKView(frame: CGRectMake(0, 0, 1024, 768))

XCPShowView("Live View", view: view)

let scene:SKScene = SKScene(size: CGSizeMake(1024, 768))
scene.scaleMode = SKSceneScaleMode.AspectFit

let aCave = Cave()

aCave.applyRules()
aCave.applyRules()

aCave.addSprite(scene)
view.presentScene(scene)
person CyberVidia    schedule 06.05.2016

Обновлен код игровой площадки для Xcode 8 и Swift 3. Я поменял местами количество ячеек X и Y, так как вы, скорее всего, увидите вид в «портретной» ориентации.

Не забудьте открыть Assistant Editor, чтобы просмотреть результаты. Выполнение также занимает некоторое время, поэтому дайте ему пару минут на запуск алгоритма.

//: Playground - noun: a place where people can play

import UIKit
import SpriteKit
import XCPlayground
import PlaygroundSupport


class Cave {

    var cellmap:[[Bool]]

    let chanceToStartAlive = 35
    let deathLimit = 3
    let birthLimit = 4
    var xCell = 20 // number of cell in x axes
    var yCell = 40 // number of cell in y axes
    var wCell = 20 // cell width
    var hCell = 20 // cell height

    init(){
        cellmap = Array(repeating:
            Array(repeating:false, count:xCell), count:yCell)

        cellmap = self.initialiseMap(xIndex: xCell, yIndex:yCell)
    }

    func initialiseMap(xIndex:Int, yIndex:Int) -> [[Bool]]{
        var map:[[Bool]] = Array(repeating:
            Array(repeating:false, count:xIndex), count:yIndex)

        for y in 0...(yIndex - 1) {
            for x in 0...(xIndex - 1) {

                let diceRoll = Int(arc4random_uniform(100))

                if diceRoll < chanceToStartAlive {
                    map[y][x] = true
                } else {
                    map[y][x] = false
                }
            }
        }
        return map
    }

    func addSprite(scene:SKScene){
        for (indexY, row) in cellmap.enumerated(){
            for (indexX, isWall) in row.enumerated(){
                if isWall {

                    let wall = SKSpriteNode(color: UIColor.red, size: CGSize(width: wCell, height: hCell))
                    wall.position = CGPoint(x: (indexX * wCell) + (wCell / 2) , y: (indexY * hCell) + (hCell / 2)  )
                    scene.addChild(wall)
                }
            }
        }
    }

    func countAliveNeighbours(x:Int, y:Int) -> Int{

        var count = 0
        var neighbour_x = 0
        var neighbour_y = 0

        for i in -1...1 {

            for j in -1...1 {

                neighbour_x = x + j
                neighbour_y = y + i


                if(i == 0 && j == 0){
                } else if(neighbour_x < 0 || neighbour_y < 0 || neighbour_y >= cellmap.count || neighbour_x >= cellmap[0].count){
                    count = count + 1
                } else if(cellmap[neighbour_y][neighbour_x]){
                    count = count + 1
                }

            }

        }

        return count

    }

    func applyRules(){

        var newMap:[[Bool]] = Array(repeating:
            Array(repeating:false, count:xCell), count:yCell)



        for y in 0...(cellmap.count - 1) {
            for x in 0...(cellmap[0].count - 1) {
                let nbs = countAliveNeighbours( x: x, y: y);
                if(cellmap[y][x]){
                    if(nbs < deathLimit){
                        newMap[y][x] = false;
                    }
                    else{
                        newMap[y][x] = true;
                    }
                } else{
                    if(nbs > birthLimit){
                        newMap[y][x] = true;
                    }
                    else{
                        newMap[y][x] = false;
                    }
                }
            }
        }
        cellmap = newMap
    }
}

let view:SKView = SKView(frame: CGRect(x: 0, y: 0, width: 768, height: 1024))

let scene:SKScene = SKScene(size: CGSize(width: 768, height: 1024))
scene.scaleMode = SKSceneScaleMode.aspectFit

PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = view

let aCave = Cave()

aCave.applyRules()
aCave.applyRules()

aCave.addSprite(scene: scene)
view.presentScene(scene)
person pfortissimo    schedule 02.10.2017