alec dsdsd
alec dsdsd

Reputation: 19

swift SceneKit decline node move

I create a sphere node, I need the user to be able only to rotate (left / right, up / down) and zoom in / out the node, but default he can move the node from the center (with two fingers) - is possible prohibit the user to move the node from the center? thanks for any help

sceneView.scene = scene

cameraOrbit = SCNNode()
cameraNode = SCNNode()
camera = SCNCamera()

// camera stuff
camera.usesOrthographicProjection = true
camera.orthographicScale = 5
camera.zNear = 1
camera.zFar = 100

cameraNode.position = SCNVector3(x: 0, y: 0, z: 70)
cameraNode.camera = camera
cameraOrbit = SCNNode()
cameraOrbit.addChildNode(cameraNode)
scene.rootNode.addChildNode(cameraNode)

let sphere = SCNSphere(radius: 2)
sphere.firstMaterial?.diffuse.contents = UIColor.red
let earthNode = SCNNode(geometry: sphere)
earthNode.name = "sphere"
earthNode.geometry?.materials = [blueMaterial]
scene.rootNode.addChildNode(earthNode)
earthNode.rotation = SCNVector4(0, 1, 0, 0)

let lightNode = SCNNode()
let light = SCNLight()
light.type = .ambient
light.intensity = 200
lightNode.light = light
scene.rootNode.addChildNode(lightNode)

sceneView.allowsCameraControl = true
sceneView.backgroundColor = UIColor.clear
sceneView.cameraControlConfiguration.allowsTranslation = true
sceneView.cameraControlConfiguration.rotationSensitivity = 0.4

Upvotes: 0

Views: 150

Answers (2)

Voltan
Voltan

Reputation: 1213

You can put similar code into your UIViewController:

//**************************************************************************
    // Gesture Recognizers
    // MARK: Gesture Recognizers
    //**************************************************************************
    @objc func handleTap(recognizer: UITapGestureRecognizer)
    {
        if(data.isNavigationOff == true) { return }         // No panel select if Add, Update, EndWave, or EndGame
        if(gameMenuTableView.isHidden == false) { return }  // No panel if game menu is showing
        
        let location: CGPoint = recognizer.location(in: gameScene)
        
        if(data.isAirStrikeModeOn == true)
        {
            let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
            let scenePoint = gameScene.unprojectPoint(SCNVector3(location.x, location.y, CGFloat(projectedPoint.z)))
            gameControl.airStrike(position: scenePoint)
        }
        else
        {
            let hitResults = gameScene.hitTest(location, options: hitTestOptions)
            for vHit in hitResults
            {
                if(vHit.node.name?.prefix(5) == "Panel")
                {
                    // May have selected an invalid panel or auto upgrade was on
                    if(gameControl.selectPanel(vPanel: vHit.node.name!) == false) { return }
                    return
                }
            }
        }
    }
    //**************************************************************************
    @objc func handlePan(recognizer: UIPanGestureRecognizer)
    {
        if(data.gameState != .run || data.isGamePaused == true) { return }
        
        currentLocation = recognizer.location(in: gameScene)
        
        switch recognizer.state
        {
        case UIGestureRecognizer.State.began:
            beginLocation = recognizer.location(in: gameScene)
            break
        case UIGestureRecognizer.State.changed:
            if(currentLocation.x > beginLocation.x * 1.1)
            {
                beginLocation.x = currentLocation.x
                gNodes.camera.strafeLeft()
            }
            if(currentLocation.x < beginLocation.x * 0.9)
            {
                beginLocation.x = currentLocation.x
                gNodes.camera.strafeRight()
            }
            break
        case UIGestureRecognizer.State.ended:
            break
        default:
            break
        }
    }

Upvotes: 1

Voltan
Voltan

Reputation: 1213

Yes, all of that is doable. First, create your own camera class and turn off allowsCameraControl. Then you can implement zoom/strafe/whatever.

Here are some examples that may help, just search for these numbers in the stack search bar and find my answers/examples.

57018359 - this post one tells you how to touch a 2d screen (tap) and translate it to 3d coordinates with you deciding the depth (z), like if you wanted to tap the screen and place an object in 3d space.

57003908 - this post tells you how to select an object with a hitTest (tap). For example, if you showed the front of a house with a door and tap it, then the function would return your door node provided you name the node "door" and took some kind of action when it's touched. Then you could reposition your camera based on that position. You'll want to go iterate through all results because there might be overlapping or plus Z nodes

55129224 - this post gives you quick example of creating a camera class. You can use this to reposition your camera or move it forward and back, etc.

Two finger drag:

func dragBegins(vRecognizer: UIPanGestureRecognizer)
    {
        if(data.gameState == .run)
        {
            if(vRecognizer.numberOfTouches == 2) { dragMode = .strafe }
        }
    }


class Camera
{
    var data = Data.sharedInstance
    var util = Util.sharedInstance
    var gameDefaults = Defaults()
    
    var cameraEye = SCNNode()
    var cameraFocus = SCNNode()
    
    var centerX: Int = 100
    var strafeDelta: Float = 0.8
    var zoomLevel: Int = 35
    var zoomLevelMax: Int = 35              // Max number of zoom levels
    
    //********************************************************************
    init()
    {
        cameraEye.name = "Camera Eye"
        cameraFocus.name = "Camera Focus"
        
        cameraFocus.isHidden = true
        cameraFocus.position  =  SCNVector3(x: 0, y: 0, z: 0)
        
        cameraEye.camera = SCNCamera()
        cameraEye.constraints = []
        cameraEye.position = SCNVector3(x: 0, y: 15, z: 0.1)
        
        let vConstraint = SCNLookAtConstraint(target: cameraFocus)
        vConstraint.isGimbalLockEnabled = true
        cameraEye.constraints = [vConstraint]
    }
    //********************************************************************
    func reset()
    {
        centerX = 100
        cameraFocus.position  =  SCNVector3(x: 0, y: 0, z: 0)
        cameraEye.constraints = []
        cameraEye.position = SCNVector3(x: 0, y: 32, z: 0.1)
        cameraFocus.position = SCNVector3Make(0, 0, 0)
        
        let vConstraint = SCNLookAtConstraint(target: cameraFocus)
        vConstraint.isGimbalLockEnabled = true
        cameraEye.constraints = [vConstraint]
    }
    //********************************************************************
    func strafeRight()
    {
        if(centerX + 1 < 112)
        {
            centerX += 1
            cameraEye.position.x += strafeDelta
            cameraFocus.position.x += strafeDelta
        }
    }
    //********************************************************************
    func strafeLeft()
    {
        if(centerX - 1 > 90)
        {
            centerX -= 1
            cameraEye.position.x -= strafeDelta
            cameraFocus.position.x -= strafeDelta
        }
    }
    //********************************************************************
}


//********************************************************************
    func lerp(start: SCNVector3, end: SCNVector3, percent: Float) -> SCNVector3
    {
        let v3 = cgVecSub(v1: end, v2: start)
        let v4 = cgVecScalarMult(v: v3, s: percent)
        return cgVecAdd(v1: start, v2: v4)
    }

Upvotes: 1

Related Questions