使用CMDeviceMotion获取绝对旋转?

时间:2014-07-14 00:02:34

标签: ios swift accelerometer gyroscope cmmotionmanager

我正在使用Sprite Kit构建一个简单的游戏,屏幕不会旋转,但我想知道用户为游戏机制持有手机的角度。

我想用加速度计(x,y)轻松检索我想要的值,但我发现这是不可靠的,所以我试图用CMDeviceMotion存档更好的结果。我可以获得相当于data.acceleration.y但我无法弄清楚如何得到data.acceleration.x的等价物。

if let data = motionManager.accelerometerData? {
    let y = CGFloat(data.acceleration.y)
    let x = CGFloat(data.acceleration.x)
}

// Device Motion
if let attitude = motionManager.deviceMotion?.attitude? {
    let y = CGFloat(-attitude.pitch * 2 / M_PI) // This matches closely with data.acceleration.y
    let x = ??????????
}

如何使用data.acceleration.x计算CMDeviceMotion的等效值?

3 个答案:

答案 0 :(得分:7)

如果您希望旋转值考虑到陀螺仪和加速度计输入,听起来您想要运动管理器的device motion。根据文件:

  

CMDeviceMotion的一个实例封装了设备的姿态,旋转速率和加速度的测量结果。

因此,不是直接监控陀螺仪数据,而是监控设备运动。下面的示例演示了如何逐帧获取设备运动。我刚刚决定直接打印CMAttitude对象,但是从这个对象中,你可以直接访问设备的俯仰,滚动和偏航(and more),如果我没弄错的话,正是你要找的。

import SpriteKit
import CoreMotion

class GameScene: SKScene {
    let motionManager = CMMotionManager()

    override func didMoveToView(view: SKView) {
        motionManager.deviceMotionUpdateInterval = 1.0 / 30.0
        motionManager.startDeviceMotionUpdates()
    }

    override func willMoveFromView(view: SKView!) {
        motionManager.stopDeviceMotionUpdates()
    }

    override func update(currentTime: CFTimeInterval) {
        if let attitude = motionManager.deviceMotion?.attitude? {
            println(attitude)
            let y = CGFloat(-attitude.pitch * 2 / M_PI)
            let x = CGFloat(-attitude.roll * 2 / M_PI)
        }
    }
}

如果您使用的是Swift 2,则需要进行一些小的更改,如下所示。

class GameScene: SKScene {
    let motionManager = CMMotionManager()

    override func didMoveToView(view: SKView) {
        motionManager.deviceMotionUpdateInterval = 1.0 / 30.0
        motionManager.startDeviceMotionUpdates()
    }

    override func willMoveFromView(view: SKView) {
        motionManager.stopDeviceMotionUpdates()
    }

    override func update(currentTime: CFTimeInterval) {
        if let attitude = motionManager.deviceMotion?.attitude {
            print(attitude)
            let y = CGFloat(-attitude.pitch * 2 / M_PI)
            let x = CGFloat(-attitude.roll * 2 / M_PI)
        }
    }
}

有关详细信息,请参阅this image

enter image description here

答案 1 :(得分:2)

您可以通过读取CoreMotion提供的陀螺仪数据来获得角度。像这样初始化一个CM对象:

class GameScene: SKScene {
    var motionManager = CMMotionManager()
    override func didMoveToView(view: SKView) {
        motionManager.startGyroUpdates()
    }
}

然后在更新功能中,您可以阅读它:

override func update(currentTime: CFTimeInterval) {
    if let data = motionManager.gyroData {
        let x = data.rotationRate.x
        let y = data.rotationRate.y
        let z = data.rotationRate.z
    }
}

您现在可以使用游戏机制的x,y和z值。但请注意,它会给出当前轮次而不是绝对轮换。如果你需要的话,你可以自己跟踪它。或者,您可以使用加速度计数据:

motionManager.startAccelerometerUpdates()
...
if let data = motionManager.accelerometerData {
    let x = data.acceleration.x
}

答案 2 :(得分:0)

这就是我现在正在尝试的。我通过实验得到了它,所以我不知道它是否正确,可能有更好的解决方案。

            if let attitude = motionManager.deviceMotion?.attitude? {
                 // Convert pitch and roll to [-1, 1] range
                let pitch = CGFloat(-attitude.pitch * 2 / M_PI)
                let roll = CGFloat(abs(attitude.roll) > M_PI / 2 ? (2 - abs(attitude.roll) * 2 / M_PI) * (attitude.roll > 0 ? 1 : -1) : attitude.roll * 2 / M_PI)

                // Calculate x and y
                let y = pitch
                let x = roll*(1.0-abs(pitch))
            }