[SceneKit专题]14.Motion Control运动控制

96
作者 史前图腾
2017.04.16 11:53* 字数 190

说明

本系列文章是对<3D iOS Games by Tutorials>一书的学习记录和部分翻译,此书对应的代码地址:https://github.com/XanderXu/3D-iOS-Games-by-Tutorials-code
系列文章目录:http://www.jianshu.com/p/fd32aa0d896a

相机约束

// 1.拿到相机节点
cameraNode = scnScene.rootNode.childNodeWithName("camera", recursively:
true)!
// 2.添加lookAt约束,让相机始终朝向ballNode小球节点
let constraint = SCNLookAtConstraint(target: ballNode)
cameraNode.constraints = [constraint]

Gimbal locking万向节锁

当使用SCNLookAtConstraint时,Scene Kit不管被朝向的对象如何移动,旋转都会让相机对着他.但是有些时候会转到一些奇怪的角度,导致相机发生向左或向右的倾斜,对于灯光是没问题的,但相机就不可以,我们总是希望相机保持水平方向.
因此用到万向节锁

constraint.gimbalLockEnabled = true

更改物体的运动状态和位置

//根据手机加速度传感器数据,移动小球
func updateMotionControl() {
    // 1.每0.1秒更新传感器参数,构造为向量
    if game.state == GameStateType.Playing {
      motion.getAccelerometerData(0.1) { (x,y,z) in
        self.motionForce = SCNVector3(x: Float(x) * 0.05, y:0, z: Float(y+0.8) * -0.05)
      }
      // 2.小球的速度改变
      ballNode.physicsBody!.velocity += motionForce
    }
  }
  
//让相机跟着小球平滑移动
  func updateCameraAndLights() {
    // 1.小球呈现位置与相机当前位置的差,每次移动0.01
    let lerpX = (ballNode.presentationNode.position.x - cameraFollowNode.position.x) * 0.01
    let lerpY = (ballNode.presentationNode.position.y - cameraFollowNode.position.y) * 0.01
    let lerpZ = (ballNode.presentationNode.position.z - cameraFollowNode.position.z) * 0.01
    cameraFollowNode.position.x += lerpX
    cameraFollowNode.position.y += lerpY
    cameraFollowNode.position.z += lerpZ
    // 2.灯光位置也跟随相机位置变化
    lightFollowNode.position = cameraFollowNode.position
    // 3.进入暂停状态时,相机欧拉角沿y轴旋转0.005
    if game.state == GameStateType.TapToPlay {
      cameraFollowNode.eulerAngles.y += 0.005
    }
  }

传感器工具类代码

import Foundation
import CoreMotion

class CoreMotionHelper {
  
  let motionManager = CMMotionManager()
  
  init() {
  }
  
  func getAccelerometerData(interval: NSTimeInterval = 0.1, closure: ((x: Double, y: Double, z: Double) -> ())? ){
    
    if motionManager.accelerometerAvailable {
      
      motionManager.accelerometerUpdateInterval = interval
      
      motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue()) {
        (data: CMAccelerometerData?, error: NSError?) -> Void in
        
        if closure != nil{
          closure!(x: data!.acceleration.x,y: data!.acceleration.y,z: data!.acceleration.z)
        }
        
      }
    }
  }
}
SceneKit