从 ViewController 访问 SceneKit-Node

Accessing SceneKit-Node from ViewController

我正在尝试在 Swift 中构建一个 SceneKit-App。这个应用程序应该有一个 SpriteKit-Overlay。我的问题是,我可以从 ViewController 中的 SpriteKit 访问 LabelNode,但不能更改 SceneKit 中 Cube-Node 的位置值,尽管我可以访问该节点。因为我是新手,所以如果有人能指出正确的方向,那就太好了。

class GameViewController: UIViewController {

    var sceneView: SCNView!
    var spriteScene: SpriteKitOverlay!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
        self.sceneView.scene = SceneKitScene()
        self.sceneView.backgroundColor = UIColor.brownColor()
        self.view.addSubview(self.sceneView)

        self.spriteScene = SpriteKitOverlay(size: self.view.bounds.size)
        self.sceneView.overlaySKScene = self.spriteScene

        SceneKitScene().cubeNode.position = SCNVector3(0,10,0)
        spriteScene.labelTest.text = "Changed label"
        print(SceneKitScene().cubeNode.position)
    }
}

class SpriteKitOverlay: SKScene {

    var labelTest: SKLabelNode!

    override init(size: CGSize) {
        super.init(size: size)

        self.labelTest = SKLabelNode(text: "Label text")
        self.labelTest.fontColor = UIColor.whiteColor()
        self.labelTest.fontSize = 24
        self.labelTest.position = CGPoint(x: size.width/2, y: size.height/2)

        self.addChild(self.labelTest)

    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

}


class SceneKitScene: SCNScene {

    var cubeNode: SCNNode!
    var cameraNode: SCNNode!
    var lightNode: SCNNode!

    override init() {
        super.init()

        let cube = SCNBox(width: 3, height: 3, length: 3, chamferRadius: 0)
        let cubeMaterial = SCNMaterial()
        cubeMaterial.diffuse.contents = UIColor.blueColor()
        cube.materials = [cubeMaterial]
        self.cubeNode = SCNNode(geometry: cube)
        self.cubeNode.position = SCNVector3(0,0,0)
        self.cubeNode.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0, y: 0.01, z: 0, duration: 1.0/60.0)))

        let camera = SCNCamera()
        camera.xFov = 60
        camera.yFov = 60

        let ambientLight = SCNLight()
        ambientLight.type = SCNLightTypeAmbient
        ambientLight.color = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0)

        let cameraConstraint = SCNLookAtConstraint(target: self.cubeNode)
        cameraConstraint.gimbalLockEnabled = true

        self.cameraNode = SCNNode()
        self.cameraNode.camera = camera
        self.cameraNode.constraints = [cameraConstraint]
        self.cameraNode.light = ambientLight
        self.cameraNode.position = SCNVector3(x: 5, y: 5, z: 5)

        let omniLight = SCNLight()
        omniLight.type = SCNLightTypeOmni

        self.lightNode = SCNNode()
        self.lightNode.light = omniLight
        self.lightNode.position = SCNVector3(x: -3, y: 5, z: 3)

        self.rootNode.addChildNode(self.cubeNode)
        self.rootNode.addChildNode(self.cameraNode)
        self.rootNode.addChildNode(self.lightNode)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }


}

当您调用 SceneKitScene().cubeNode.position = SCNVector3(0,10,0) 时,您正试图在新创建的 SceneKitScene 上更改 cubeNode.position

尝试将您的 GameViewController 更改为:

class GameViewController: UIViewController {

    var sceneView: SCNView!
    // create new instance variable to hold current sceneKitScene
    var sceneKitScene: SceneKitScene!
    var spriteScene: SpriteKitOverlay!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
        // save SceneKitScene to instance variable
        self.sceneKitScene = SceneKitScene()
        self.sceneView.scene = self.sceneKitScene
        self.sceneView.backgroundColor = UIColor.brownColor()
        self.view.addSubview(self.sceneView)

        self.spriteScene = SpriteKitOverlay(size: self.view.bounds.size)
        self.sceneView.overlaySKScene = self.spriteScene

        // update cubeNode position in active sceneKitScene
        sceneKitScene.cubeNode.position = SCNVector3(0,10,0)
        spriteScene.labelTest.text = "Changed label"
        print(SceneKitScene().cubeNode.position)
    }
}

这会创建一个新的实例变量来保存您当前的 SceneKitScene(与您对当前 SpriteKitOverlay 所做的相同)。然后你可以使用这个变量来访问和更新当前 cubeNode 在屏幕上的位置。