BSP Dungeon Generator 给出无法修复的错误

Posted

技术标签:

【中文标题】BSP Dungeon Generator 给出无法修复的错误【英文标题】:BSP Dungeon Generator giving an unfixable error 【发布时间】:2019-03-06 12:07:10 【问题描述】:

我正在努力将关于二进制空间分区的this ActionScript tutorial 翻译成 Swift,以便我可以在我的流氓游戏中使用它。我遇到了一个障碍。

在文章中,作者这样初始化他的类:

public function Leaf(X:int, Y:int, Width:int, Height:int)

    // initialize our leaf
    x = X;
    y = Y;
    width = Width;
    height = Height;

当我把它翻译成 Swift 时,我遇到了一个错误。上面的代码并没有初始化它所有的声明值。这使我陷入了一个似乎无法修复的不可能错误。不知何故,这篇文章的作者用这个超出初始化范围的函数初始化了他的leftChildrightChild 变量。

public function split():Boolean

    // begin splitting the leaf into two children
    if (leftChild != null || rightChild != null)
        return false; // we're already split! Abort!

    // determine direction of split
    // if the width is >25% larger than height, we split vertically
    // if the height is >25% larger than the width, we split horizontally
    // otherwise we split randomly
    var splitH:Boolean = FlxG.random() > 0.5;
    if (width > height && width / height >= 1.25)
        splitH = false;
    else if (height > width && height / width >= 1.25)
        splitH = true;

    var max:int = (splitH ? height : width) - MIN_LEAF_SIZE; // determine the maximum height or width
    if (max <= MIN_LEAF_SIZE)
        return false; // the area is too small to split any more...

    var split:int = Registry.randomNumber(MIN_LEAF_SIZE, max); // determine where we're going to split

    // create our left and right children based on the direction of the split
    if (splitH)
    
        leftChild = new Leaf(x, y, width, split);
        rightChild = new Leaf(x, y + split, width, height - split);
    
    else
    
        leftChild = new Leaf(x, y, split, height);
        rightChild = new Leaf(x + split, y, width - split, height);
    
    return true; // split successful!

这在 ActionScript 中是可以的,但在 Swift 中却引出了我的问题。

这是我的翻译代码(Swift):

private let mapWidth:Int = 50
private let mapHeight:Int = 50

class Leaf 
    var leftLeaf = [Leaf]()
    var rightLeaf = [Leaf]()

    var minLeafSize:Int = 6
    var x, y, width, height: Int

    var leftChild:Leaf
    var rightChild:Leaf

    init (X:Int, Y:Int, W:Int, H:Int) 

        x = Y
        y = Y

        width = W
        height = H

        let maxLeafSize:UInt = 20

        var leaves = [Leaf]()

        // first, create a Leaf to be the 'root' of all Leafs.
        let root = Leaf(X: 0, Y: 0, W: mapWidth, H: mapHeight)
        leaves.append(root)

        var didSplit:Bool = true
        // we loop through every Leaf in our Vector over and over again, until no more Leafs can be split.
        while (didSplit) 
            didSplit = false
            for l in leaves 
                if l.leftLeaf.isEmpty == true && l.rightLeaf.isEmpty == true 
                    // if this Leaf is too big, or 75% chance...
                    if l.width > maxLeafSize || l.height > maxLeafSize || Int(arc4random_uniform(100)) > 25 
                        if (l.split()) 
                            // if we did split, push the child leafs to the Vector so we can loop into them next
                            leaves.append(l.leftChild)
                            leaves.append(l.rightChild)
                            didSplit = true
                        
                    
                
            
        
    
    func split() -> Bool 
        if leftLeaf.isEmpty == true || rightLeaf.isEmpty == true 
            return false
        

        var splitH = arc4random_uniform(100) > 50 ? true : false

        if width > height && Double(width / height) >= 1.25 
            splitH = false
        
        if height > width && Double(height / width) >= 1.25 
            splitH = true
        

        let max:Int = (splitH ? height : width) - minLeafSize // determine the maximum height or width
        if max <= minLeafSize  return false 

        let split:Int = Int(arc4random_uniform(UInt32(minLeafSize - max) + UInt32(max)))

        if (splitH) 
            leftChild = Leaf(X: x, Y: y, W: width, H: split)
            rightChild = Leaf(X: x, Y: y + split, W: width, H: height - split)

            leftLeaf.append(leftChild)
            rightLeaf.append(rightChild)
         else 
            leftChild = Leaf(X: x, Y: y, W: split, H: height)
            rightChild = Leaf(X: x + split, Y: y, W: width - split, H: height);

            leftLeaf.append(leftChild)
            rightLeaf.append(rightChild)
        
        return true
    

它与文章中的 ActionScript 代码相同(据我所知)。但这给了我一个错误。 leftChildrightChild 变量未在我的 init 方法中初始化。当我将split() -&gt; Bool 函数移动到init 方法中时,它不会让我使用该函数,给我一个错误“Leaf 类型的值没有成员 split()”。从if (l.spit()) 行中删除l 会给我第二个错误“在声明之前使用局部变量'split'”。 split() 函数必须在初始化范围之外。

如果我尝试像这样初始化 leftChildrightChild

init (X:Int, Y:Int, W:Int, H:Int) 

    x = Y
    y = Y

    width = W
    height = H

    leftChild = Leaf(X: x, Y: y, W: width, H: height)
    rightChild = Leaf(X: x, Y: y, W: width, H: height)

它会创建一个无限循环,最终导致崩溃。

代码应该在split() -&gt; Bool 函数中初始化leftChildrightChild,但我认为这不是它在Swift 中的工作方式。您应该能够将其复制/粘贴到 Swift 文件中并得到相同的错误。

为什么会这样?我的代码写得不好?我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

在 ActionScript 中,未初始化的变量会自动使用特殊值 undefined 进行评估;同样,在 ActionScript 中,undefined == null,这就是 if (leftChild != null || rightChild != null) 起作用的原因。

在 Swift 中,您需要显式地 allow 您的变量是可空的。您担心的变量需要以 nil 开头(如果您允许,它们会自动将其类型设置为 Optional - 注意问号):

var leftChild:Leaf?
var rightChild:Leaf?

【讨论】:

快速回答!我无法弄清楚作者是如何完成他的代码的。我根据您的回答修复了我的代码,它现在似乎可以工作了。我以前从未研究过任何 ActionScript。所以我自己不可能解决这个问题。

以上是关于BSP Dungeon Generator 给出无法修复的错误的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2251 Dungeon Master --- 三维BFS(用BFS求最短路)

Dungeon Master

174. Dungeon Game

java 174. Dungeon Game(#1).java

java 174. Dungeon Game(#1).java

java 174. Dungeon Game(#1).java