2
votes

Swift 3, SceneKit: In my game, I have an SCNSphere node in the center of the screen. The sphere drops by gravity onto an SCNBox node, and a velocity of SCNVector3(0,6,0) is applied to it once it collides with the box.

A new box is created and moves forward (z+) towards my camera and towards the sphere as well. The sphere rises, peaks, and then falls back down (by gravity) towards the new box, and when it collides with the new box, a velocity of SCNVector(0,6,0) is applied to it. This process repeats continuously. A sphere that repeatedly bounces on a new approaching box, basically.

Instead of just one box, however, there will be three boxes in a row. All boxes begin in front of the sphere node and move towards it when they are created, the boxes are placed in a row, one to the left of the sphere, one directly in front of the sphere (the middle), and the third to the right of the sphere.

I want to be able to drag my finger across the screen and move my sphere so that it can land on the left and right boxes. While I'm dragging, I do not want the y-velocity or y-position to be changed at all. I just want the x-position of my sphere node to mirror the real-world x-position of my finger relative to the screen. I also do not want the sphere node to change location based on a touch alone.

For example, if the sphere's position is at SCNVector3(2,0,0), and if the user taps near SCNVector3(-2,0,0), I do not want the sphere to "teleport" to where the user tapped. I want the user to drag the sphere from its last position.

func handlePan(recognizer: UIPanGestureRecognizer) {

    let sceneView = self.view as! SCNView
    sceneView.delegate = self
    sceneView.scene = scene


    let trans:SCNVector3 = sceneView.unprojectPoint(SCNVector3Zero)
    let pos:SCNVector3 = player.presentation.position
    let newPos = (trans.x) + (pos.x)
    player.position.x = newPos
}
1

1 Answers

4
votes

I just want the x-position of my sphere node to mirror the real-world x-position of my finger relative to the screen

You can do this by using UIPanGestureRecognizer and getting the translation in the coordinate system of the view.

let myPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
let trans2D:CGPoint = myPanGestureRecognizer.translation(in:self.view)
let transPoint3D:SCNVector3 = SCNVector3Make(trans2D.x, trans2D.y, <<z>>)

For z value, refer to the unProjectPoint Discussion, which says that z should refer to the depth at which you want to un-project relative to the near and far clipping planes of your view frustum.

You can then un-project the translation to the 3D world coordinate system of the scene, which will give you the translation for the sphere node. Some partial sample code:

let trans:SCNVector3 = sceneView.unProjectPoint(transPoint3D)
let pos:SCNVector3 = sphereNode.presentationNode.position
let newPos:SCNVector3 = // trans + pos
sphereNode.position = newPosition