Created
April 9, 2022 10:51
-
-
Save danmonaghan/f4eafa84cfb0bd22ec68f5b55ba8aeee to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GameViewController.swift | |
// StackTrackBall | |
// | |
// Created by Dan Monaghan on 9/04/22. | |
// | |
import UIKit | |
import QuartzCore | |
import SceneKit | |
class GameViewController: UIViewController { | |
var cameraOrbit = SCNNode() | |
let orbitCameraNode = SCNNode() | |
let orbitCamera = SCNCamera() | |
//HANDLE PAN CAMERA | |
var lastWidthRatio: Float = 0 | |
var lastHeightRatio: Float = 0.2 | |
var fingersNeededToPan = 1 | |
var maxWidthRatioRight: Float = 1000 | |
var maxWidthRatioLeft: Float = 1000 | |
var maxHeightRatioXDown: Float = 1000 | |
var maxHeightRatioXUp: Float = 1000 | |
//HANDLE PINCH CAMERA | |
var pinchAttenuation = 20.0 //1.0: very fast ---- 100.0 very slow | |
var lastFingersNumber = 0 | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// create a new scene | |
let scene = SCNScene(named: "art.scnassets/ship.scn")! | |
// create and add a light to the scene | |
let lightNode = SCNNode() | |
lightNode.light = SCNLight() | |
lightNode.light!.type = SCNLight.LightType.omni | |
lightNode.position = SCNVector3(x: 0, y: 10, z: 10) | |
scene.rootNode.addChildNode(lightNode) | |
// create and add an ambient light to the scene | |
let ambientLightNode = SCNNode() | |
ambientLightNode.light = SCNLight() | |
ambientLightNode.light!.type = SCNLight.LightType.ambient | |
ambientLightNode.light!.color = UIColor.darkGray | |
scene.rootNode.addChildNode(ambientLightNode) | |
//Create a camera like Rickster said | |
// let camera = SCNCamera() | |
// camera.usesOrthographicProjection = true | |
// camera.orthographicScale = 9 | |
// camera.zNear = 0 | |
// camera.zFar = 100 | |
// let cameraNode = SCNNode() | |
// cameraNode.position = SCNVector3(x: 0, y: 0, z: 50) | |
// cameraNode.camera = camera | |
// let cameraOrbit = SCNNode() | |
// cameraOrbit.addChildNode(cameraNode) | |
// cubeScene.rootNode.addChildNode(cameraOrbit) | |
// | |
orbitCamera.zNear = 1 | |
orbitCamera.zFar = 100 | |
orbitCamera.motionBlurIntensity = 0.6 | |
orbitCameraNode.position = SCNVector3(x: 0, y: 0, z: 4) | |
orbitCameraNode.camera = orbitCamera | |
cameraOrbit = SCNNode() | |
cameraOrbit.addChildNode(orbitCameraNode) | |
scene.rootNode.addChildNode(cameraOrbit) | |
//initial camera setup | |
self.cameraOrbit.eulerAngles.y = Float(-2 * Float.pi) * lastWidthRatio | |
self.cameraOrbit.eulerAngles.x = Float(-Float.pi) * lastHeightRatio | |
// retrieve the SCNView | |
let scnView = self.view as! SCNView | |
// set the scene to the view | |
scnView.scene = scene | |
scnView.showsStatistics = true | |
//allows the user to manipulate the camera | |
scnView.allowsCameraControl = false //not needed | |
// add a tap gesture recognizer | |
let panGesture = UIPanGestureRecognizer(target: self, action:#selector(handlePan)) | |
scnView.addGestureRecognizer(panGesture) | |
// add a pinch gesture recognizer | |
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch)) | |
scnView.addGestureRecognizer(pinchGesture) | |
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotate)) | |
scnView.addGestureRecognizer(rotateGesture) | |
} | |
let dollySpeed : Float = 2000 | |
let zRollModifier : Float = 5 | |
let panModifier = 100 | |
let pinchModifier : Float = 15 | |
let maxZoomIn : Float = -1000.0 | |
let maxZoomOut : Float = 1000.0 | |
@objc func handleRotate(recognizer: UIRotationGestureRecognizer) { | |
let scale = recognizer.velocity | |
print("scale =\(scale)") | |
cameraOrbit.eulerAngles.z += Float(scale / CGFloat(zRollModifier)).radians | |
} | |
@objc func handlePan(gestureRecognize: UIPanGestureRecognizer) { | |
if gestureRecognize.numberOfTouches == 1 { | |
let numberOfTouches = gestureRecognize.numberOfTouches | |
let translation = gestureRecognize.velocity(in: gestureRecognize.view!) | |
cameraOrbit.eulerAngles.y -= Float(translation.x/CGFloat(panModifier)).radians | |
cameraOrbit.eulerAngles.x -= Float(translation.y/CGFloat(panModifier)).radians | |
} | |
if gestureRecognize.numberOfTouches == 2 { | |
let scale = gestureRecognize.velocity(in: gestureRecognize.view!) | |
print("scale =\(scale)") | |
let translation = gestureRecognize.translation(in: gestureRecognize.view!) | |
let xx = orbitCameraNode.position.x - Float(scale.x) / dollySpeed | |
if xx < maxZoomOut, xx > maxZoomIn { | |
orbitCameraNode.position.x = xx | |
} | |
let yy = orbitCameraNode.position.y + Float(scale.y) / dollySpeed | |
if yy < maxZoomOut, yy > maxZoomIn { | |
orbitCameraNode.position.y = yy | |
} | |
} | |
} | |
@objc func handlePinch(recognizer: UIPinchGestureRecognizer) { | |
// guard let camera = cameraOrbit.childNodes.first else { | |
// return | |
// } | |
let scale = recognizer.velocity | |
print("scale =\(scale)") | |
let z = orbitCameraNode.position.z - Float(scale)/Float(pinchModifier) | |
if z < maxZoomOut, z > maxZoomIn { | |
orbitCameraNode.position.z = z | |
} | |
} | |
//@objc func handlePinch(gestureRecognize: UIPinchGestureRecognizer) { | |
// let pinchVelocity = Double.init(gestureRecognize.velocity) | |
// //print("PinchVelocity \(pinchVelocity)") | |
// | |
// camera.orthographicScale -= (pinchVelocity/pinchAttenuation) | |
// | |
// if camera.orthographicScale <= 0.5 { | |
// camera.orthographicScale = 0.5 | |
// } | |
// | |
// if camera.orthographicScale >= 10.0 { | |
// camera.orthographicScale = 10.0 | |
// } | |
// | |
//} | |
//override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { | |
// return .Landscape | |
//} | |
override func didReceiveMemoryWarning() { | |
super.didReceiveMemoryWarning() | |
// Release any cached data, images, etc that aren't in use. | |
} | |
} | |
extension Float { | |
var radians: Float { | |
return self * .pi / 180 | |
} | |
var degrees: Float { | |
return self * 180 / .pi | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment