场景工具包(Swift):取消隐藏或重新添加隐藏/删除的节点

Scene kit (Swift): Unhide or re-add hidden / removed nodes

我正在尝试创建一个游戏,在该游戏中,有人点击一个框,它就会消失。我的问题是 'restarting' 游戏和重新添加所有以前隐藏/删除的盒子。

我像这样创建了一排框:

func addBoxes() {

    for _ in 0..<5 {

        let sphereGeometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
        let sphereNode: SCNNode! = SCNNode(geometry: sphereGeometry)
        sphereNode.position = SCNVector3(x: x, y: y, z: z)

        scnScene.rootNode.addChildNode(sphereNode)
}

之后我当然会更新 x、y 和 z 的位置。

这一切都很完美,我隐藏了一个点击框,如下所示:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    let touch = touches.first!
    let location = touch.location(in: scnView)
    let hitResults = scnView.hitTest(location, options: nil)

    if let result = hitResults.first {

        let node = result.node
        node.isHidden = true
    }
}

点击并隐藏所有框后,游戏现在应该简单地重置,所以取消隐藏所有框:

func newGame() {

    // I've tried this and various versions of it, with no success
    for child in scnScene.rootNode.childNodes {

        child.isHidden = false
    }
}

然而,这给了我:

fatal error: unexpectedly found nil while unwrapping an Optional value

我也尝试过 child.removeFromParentNode() 然后尝试将节点重新添加到场景中,但这会引发相同的错误。

任何人都可以在这里指出正确的方向吗?如何取消隐藏在 for 循环中创建的一个或所有节点?

隐藏和取消隐藏工作正常,如下所示:

var targetsToDo: Int = 0
let maximumNumberOfTargets = 5

func loadGame() {
    targetsToDo = maximumNumberOfTargets

    scnScene = SCNScene()
    scnView.scene = scnScene

    for i in 1...maximumNumberOfTargets {
        let box = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0.1)
        let node = SCNNode(geometry: box)
        node.name = "Box \(i)"
        scnScene.rootNode.addChildNode(node)
        node.position = getRandomPosition()
    }
}

@objc func handleTouch(recognizer: UITapGestureRecognizer) {
    let point = recognizer.location(in: view)
    print("Touch at \(NSStringFromCGPoint(point))")
    if let node = scnView.hitTest(point).first?.node {
        print(node.name ?? "")
        node.isHidden = true
        targetsToDo -= 1

        if targetsToDo == 0 {
            resetGame()
        }
    }
}

func resetGame() {
    targetsToDo = maximumNumberOfTargets

    for child in scnScene.rootNode.childNodes {
        child.isHidden = false
        child.position = getRandomPosition()
    }
}

可以找到一个完整的可用游乐场 here