我正在使用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
的等效值?
答案 0 :(得分:7)
如果您希望旋转值考虑到陀螺仪和加速度计输入,听起来您想要运动管理器的device motion。根据文件:
CMDeviceMotion的一个实例封装了设备的姿态,旋转速率和加速度的测量结果。
因此,不是直接监控陀螺仪数据,而是监控设备运动。下面的示例演示了如何逐帧获取设备运动。我刚刚决定直接打印CMAttitude
对象,但是从这个对象中,你可以直接访问设备的俯仰,滚动和偏航(and more),如果我没弄错的话,正是你要找的。 p>
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。
答案 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))
}