2015-12-03 3 views
2

Я искал способ добавить смещение к тому, как акселерометр отслеживает движение игрока в моей игре. В моей игре вы управляете персонажем игрока, наклоняя телефон вперед и назад. Это переводится акселерометром на координаты x и y на экране. к сожалению, это означает, что для того, чтобы остановить персонажа от постоянного присутствия в нижней части экрана, вы должны держать телефон плоским. Что не очень удобно для игроков.Быстрая настройка отслеживания акселерометра с CMMotionManager

Таким образом, я пытаюсь реализовать способ, которым независимо от угла телефона, когда он начинает сеанс игры, то есть угол по умолчанию, а затем угол наклона определяется дельтами этого угла, а не сырой данные, которые были бы против 0,0 я думаю ...

вот моя попытка выяснить это:

func instantiateAcceleration() { 
    if motionManager.accelerometerAvailable{ 
     let queue = NSOperationQueue() 


     motionManager.startAccelerometerUpdatesToQueue(queue) { data, error in 
      let currentX = self.player.position.x 
      let currentY = self.player.position.y 

      if(!self.hasCapturedOffset){ 

       /* So the first time we enter this loop. we'll cature the offset */ 

       self.offsetY = data!.acceleration.y; 
       self.offsetX = data!.acceleration.x; 

       print("captured offset : x - \(self.offsetX) y - \(self.offsetY)") 
       self.hasCapturedOffset = true; 
      } 

      /* x coords */ 
      if data!.acceleration.y < (0 - self.offsetY) { 
       self.destX = currentX + CGFloat(data!.acceleration.y * 100) 
      } 

      else if data!.acceleration.y > (0 + self.offsetY) { 
       self.destX = currentX + CGFloat(data!.acceleration.y * 100) 
      } 

      /* y coords */ 
      if data!.acceleration.x > (0.1 - self.offsetX){ 
       self.destY = currentY - CGFloat(data!.acceleration.x * 100) 
      } 

      else if data!.acceleration.x < (0.1 + self.offsetX) { 
       self.destY = currentY - CGFloat(data!.acceleration.x * 100) 
      } 

      /* keep it in bounds */ 
      if(self.destY > self.size.height){ 
       self.destY = self.size.height; 

      }else if(self.destY < 0){ 
       self.destY = 0; 
      } 

      if(self.destX > self.size.width){ 
       self.destX = self.size.width; 

      }else if(self.destX < 0){ 
       self.destX = 0; 
      } 

     } 

    } else { 
     print("Accelerometer is not available") 
    } 

} 

что выше FUNC называется на viewDidLoad и self.DestX, self.DestY используются для обновления плеера в методе обновления:

override func update(currentTime: CFTimeInterval) { 
    /* Called before each frame is rendered */ 
    /* Accelerometer data */ 
    let action = SKAction.moveTo(CGPoint(x:destX, y:destY), duration: 0.1) 
    self.player.runAction(action) 

} 

Мне бы очень хотелось узнать, как это сделать должным образом, я знаю, что за этим стоит определенная математика, что я не знаком. Если кто-то может мне точку в правильном направлении, я бы очень признателен :)

ответ

2

Вы можете сохранять начальную ориентацию, как referenceAttitude и использовать

currentattitude.multiplyByInverseOfAttitude(referenceAttitude) 

для расчета движения.

Вот пример кода я сделал некоторое время назад:

import Foundation 
import CoreMotion 

// Damping factor 
let cLowPassFactor: Float = 0.95 

class MotionManagerSingletonSwift: NSObject { 


var motionManager: CMMotionManager 
var referenceAttitude:CMAttitude?=nil 
var bActive = false 
var lastVector:[Float] = [0.0, 0.0, 0.0] 


override init() { 
    motionManager=CMMotionManager() 
    motionManager.deviceMotionUpdateInterval = 0.25 
    motionManager.startDeviceMotionUpdates() 
    bActive=true; 
} 

// only one instance of CMMotionManager can be used in your project. 
// => Implement as Singleton which can be used in the whole application 
class var sharedInstance: MotionManagerSingletonSwift { 
struct Singleton { 
    static let instance = MotionManagerSingletonSwift() 
    } 
    return Singleton.instance 
} 

class func getMotionManager()->CMMotionManager { 
    if (sharedInstance.bActive==false) { 
     sharedInstance.motionManager.startDeviceMotionUpdates() 
     sharedInstance.bActive=true; 

    } 
    return sharedInstance.motionManager 
} 

// Returns an array with the movements 
// At the first time a reference orientation is saved to ensure the motion detection works 
// for multiple device positions 
class func getMotionVectorWithLowPass() -> [Float] { 
    // Motion 
    var attitude: CMAttitude? = getMotionManager().deviceMotion?.attitude 

    if sharedInstance.referenceAttitude==nil { 
     // Cache Start Orientation to calibrate the device. Wait for a short time to give MotionManager enough time to initialize 
     dispatch_after(250, dispatch_get_main_queue(), { 
      MotionManagerSingletonSwift.calibrate() 
      }) 
    } else if attitude != nil { 
     // Use start orientation to calibrate 
     attitude!.multiplyByInverseOfAttitude(sharedInstance.referenceAttitude) 
    } 

    if attitude != nil { 
     return lowPassWithVector([Float(attitude!.yaw), Float(attitude!.roll), Float(attitude!.pitch)]) 
    } else { 
     return [0.0, 0.0, 0.0] 
    } 
} 

// Stop collection motion data to save energy 
class func stop() { 
    sharedInstance.motionManager.stopDeviceMotionUpdates() 
    sharedInstance.referenceAttitude=nil 
    sharedInstance.bActive=false 
} 

// Calibrate motion manager with a ne reference attitude 
class func calibrate() { 
    sharedInstance.referenceAttitude = getMotionManager().deviceMotion?.attitude?.copy() as? CMAttitude 
} 


// Damp the jitter caused by hand movement 
class func lowPassWithVector(var vector:[Float]) -> [Float] 
{ 
    vector[0] = vector[0] * cLowPassFactor + sharedInstance.lastVector[0] * (1.0 - cLowPassFactor) 
    vector[1] = vector[1] * cLowPassFactor + sharedInstance.lastVector[1] * (1.0 - cLowPassFactor) 
    vector[2] = vector[2] * cLowPassFactor + sharedInstance.lastVector[2] * (1.0 - cLowPassFactor) 

    sharedInstance.lastVector = vector 
    return sharedInstance.lastVector 
} 
} 

Полный учебник: http://developerplayground.net/?p=19

+0

большое спасибо! Я попытаюсь приспособить этот подход к моему коду – agovan

+0

Возможно, глупый вопрос, но я полагаю, что массив float, который вы создаете для lastvector, имеет значения x, y, z в этом порядке? Так что, если бы я мог отвлечься от этого, я бы создал экземпляр MotionManger в viewDidLoad, а затем вызвал lastVector и вычислил свою позицию каждый галочку в обновлении? – agovan