[SceneKit專題]14-Motion-Control運動控制

蘋果API搬運工發表於2017-12-25

說明

本系列文章是對<3D Apple Games by Tutorials>一書的學習記錄和體會

此書對應的程式碼地址

SceneKit系列文章目錄

相機約束

// 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)
        }
        
      }
    }
  }
}
複製程式碼

相關文章