swift - Poisson Disk Generator 排除了四个 View 象限中的三个

标签 swift algorithm

我正在尝试在 SpriteKit 中创建一个游戏,我需要一种布局对象的方法,将它们放置在随机生成的点中对我来说不是这样,太多的分组。

经过一些研究,泊松圆盘生成器看起来正是我需要的。

我已经尝试实现我自己的。但是,所有位置都关闭了,它们丢失了显示的 3/4。

我哪里错了?

最小半径为 100。

r = 100

最小半径为 10。

r = 10

class GameScene: SKScene {

    var radius = 100
    var lookUpCount = 30
    var grid = [CGPoint?](), ordered = [CGPoint](), active = [CGPoint]()
    var w = CGFloat()
    var cols = Int()
    var rows = Int()
    var sizeScren = CGSize()


    override func didMove(to view: SKView) {
        generate()

        for item in ordered {
            let gamePiece = SKSpriteNode(imageNamed: "Spaceship")
            gamePiece.setScale(0.0625)
            gamePiece.position = item
            addChild(gamePiece)
        }
    }

    func distance(p1: CGPoint, p2: CGPoint) -> CGFloat {
        let dx = p1.x - p2.x
        let dy = p1.y - p2.y
        return sqrt(dx * dx + dy * dy)
    }

    func generateRandomPointAround(point: CGPoint, minDist: CGFloat) -> CGPoint
    {

        let rd1 = CGFloat(Float(arc4random()) / Float(UINT32_MAX))
        let rd2 = CGFloat(Float(arc4random()) / Float(UINT32_MAX))

        //random radius
        let radius = minDist * (rd1 + 1)
        //random angle
        let angle = 2 * CGFloat.pi * rd2

        //new point is generated around the point (x, y)

        let newX = point.x + radius * cos(angle)
        let newY = point.y + radius * sin(angle)
        return CGPoint(x: newX, y: newY)

    }


    func generate() {


        sizeScren = UIScreen.main.bounds.size

        //create cell
        w = (CGFloat(Double(radius) / sqrt(2)))
        cols = Int(floor(sizeScren.height / w))
        rows = Int(floor(sizeScren.width / w))

        grid = [CGPoint?](repeating: nil, count: (cols * rows))

        let x = sizeScren.height / 2
        let y = sizeScren.width / 2
        let i = floor(x / w)
        let j = floor(y / w)

        //first posistion

        let pos = CGPoint (x: frame.midX, y: frame.midY)
        let index = Int(i + j * CGFloat(cols))
        grid[index] = pos
        active.append(pos)

        while (active.count > 0) {
            let randomIndex = Int(arc4random_uniform(UInt32(active.count)))
            let currentPos = active[randomIndex]
            var found = false
            Mainloop: for _ in 0..<Int(lookUpCount) {

                let samplePoint = generateRandomPointAround(point: currentPos, minDist: CGFloat(radius))

                let col = floor(samplePoint.x / w)
                let row = floor(samplePoint.y / w)

                //check neighbouring cells are empty and valid, if have a point in already

                if (col > -1 && row > -1 && CGFloat(col) < CGFloat(cols) && CGFloat(row) < CGFloat(rows) && (grid[Int(col + CGFloat(row) * CGFloat(cols))] == nil)) {
                    var ok = true
                    for index1 in -1...1 {
                        for index2 in -1...1 {

                            //break down complexity for swift compiler

                            let part1 = Int(col + CGFloat(index1))
                            let part2 = Int(row + CGFloat(index2))
                            let part3 = part1 + part2 * cols
                            let sampleIndex = part3

                            let isIndexValid = grid.indices.contains(sampleIndex)

                            if isIndexValid {
                                let neighbor = grid[sampleIndex]

                                if neighbor != nil {
                                    let distanceAmount = distance(p1: samplePoint, p2: neighbor!)
                                    if distanceAmount < CGFloat(radius) {
                                        ok = false
                                    }

                                }

                            }
                        }
                    }

                    if (ok == true) {
                        found = true
                        grid[Int(col + row * CGFloat(cols))] = samplePoint
                        active.append(samplePoint)
                        ordered.append(samplePoint)
//                        break MainLoop
                    }
                }
            }

            if (!found) {
                active.remove(at: randomIndex)
            }
        }


    }
}

最佳答案

(0,0)为屏幕中心,samplePoint除以w转换为行列索引。然后用这个测试过滤掉所有负数的行和列索引:if (col > -1 && row > -1 ...samplePoint 在此之后没有调整,所以这将有效地删除 4 个象限中的 3 个。要解决此问题,您可以像这样偏移索引:

let col = floor((samplePoint.x + x) / w)
let row = floor((samplePoint.y + y) / w)

(xy 已经分别定义为屏幕宽度和高度的一半)

关于swift - Poisson Disk Generator 排除了四个 View 象限中的三个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44626367/

相关文章:

Swift 3 重复生成 SKNode

swift - 需要帮助调试我的 SpriteKit 应用程序中的崩溃

swift - FIRE UserProfileChangeRequest 存储数据的地方

c++ - 从图像制作多边形的算法

algorithm - 3SUM 有一个转折

ios - Obj-C 框架返回 nil,并使我的 Swift 代码崩溃并显示 'fatal error: unexpectedly found nil while unwrapping an Optional value'

swift - 类型 'CustomObject' 的值不符合预期的字典值类型 'AnyObject'

python - 在 Python 中创建唯一对象数组

python - 最接近用户输入的数字

algorithm - 修改整数一位数的最快方法