Search code examples
swiftuikitscenekitscncamera

How to move around in a SceneKit scene?


In my macCatalyst app, I try to make a SCNScene where the user should be able to move around (with w, a, s and d) but It doesn't work. I want

  • to make the possibility to just move around in the scene first
  • and then adjust it to the direction that the camera is facing

But I have already failed with the first step.

I tried to set the SCNView's point of view to a new SCNNode and tried to move that around:

// initializing the scene
let scene = SCNScene(named: "SceneKit Scene.scn")!
sceneView.scene = scene
// try to set the point of the scene
let node = SCNNode()
node.position = SCNVector3(x: 10, y: 10, z: 10)
sceneView.pointOfView = node

But it changed nothing.

I have also tried to move the node (that is holding all other nodes of the scene inside around)

override func pressesBegan(_ presses: Set<UIPress>, 
                          with event: UIPressesEvent) {

    guard let press = presses.first else { return }
    guard let key = press.key else { return }

    if key.charactersIgnoringModifiers == "w" {
        node.position.z += 1
    }
}

Which does work better, but it does not feel like going around in the scene, and if I move around the facing of the camera, I move into the wrong direction.

So how do I fix this?


Solution

  • WASD keys for movement

    Try this approach (it perfectly works on macOS app but I didn't test it on macCatalyst app):

    import SceneKit
    
    class GameViewController: NSViewController {        
        var sceneView = SCNView(frame: .zero)
        let scene = SCNScene(named: "ship.scn")!
        let cameraNode = SCNNode()
        
        override func keyDown(with event: NSEvent) {
            for char in event.characters! {
                switch char {
                    case "w" : cameraNode.position.z -= 0.5
                               print("Camera Moves Forward")
                    case "s" : cameraNode.position.z += 0.5
                               print("Camera Moves Backward")
                    case "a" : cameraNode.position.x -= 0.5
                               print("Camera Moves Left")
                    case "d" : cameraNode.position.x += 0.5
                               print("Camera Moves Right")
                    default : break
                }
            }
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            sceneView = self.view as! SCNView
            sceneView.scene = scene
            sceneView.allowsCameraControl = false
            
            cameraNode.camera = SCNCamera()
            cameraNode.position.z = 10.0
            sceneView.pointOfView = cameraNode
            sceneView.scene?.rootNode.addChildNode(cameraNode)
        }
    }
    

    Also, you can use keyCode instance property:

    override func keyDown(with event: NSEvent) {
        
        let code: UInt16 = event.keyCode
        
        if code == 13 {
            cameraNode.position.z -= 0.5; print("Camera Moves Forward")
        } else if code == 1 {
            cameraNode.position.z += 0.5; print("Camera Moves Backward")
        } else if code == 0 {
            cameraNode.position.x -= 0.5; print("Camera Moves Left")
        } else if code == 2 {
            cameraNode.position.x += 0.5; print("Camera Moves Right")
        }
    }