4

我正在使用 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.xusing CMDeviceMotion

4

3 回答 3

8

如果您希望旋转值将陀螺仪和加速度计输入考虑在内,听起来您想要运动管理器的设备运动。根据文档:

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

因此,与其直接监控陀螺仪数据,不如监控设备运动。下面的示例演示了如何逐帧获取设备运动。我刚刚决定CMAttitude直接打印对象,但是从这个对象中,您可以直接访问设备的俯仰、滚动和偏航(以及更多),如果我没记错的话,这正是您正在寻找的.

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)
        }
    }
}

有关这方面的更多信息,请参阅此图片

在此处输入图像描述

于 2014-07-20T21:15:12.003 回答
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
}
于 2014-07-14T09:04:06.593 回答
0

This is what I'm trying now. I got to it through experimentation so I cannot tell if it's correct, probably there is a better solution.

            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))
            }
于 2014-08-01T18:32:18.150 回答