Question

I'm building a "marble" labyrinth game in order to learn spritekit basics.

I want to map the gravity of the game to the tilt of the device. I've been trying to figure out how to do it but I've only been able to map the y axis successfully:

class func obtainGravity(motionManager: CMMotionManager) {
    var vec = CGVectorMake(0, 0)
    if let attitude = motionManager.deviceMotion?.attitude? {
        let y = CGFloat(-attitude.pitch * 2 / M_PI) // This works, it returns 1/-1 when the device is vertical (1 when the home button is upside down)
        let x = CGFloat(attitude.roll * 2 / M_PI) // This doesn't work
        physicsWorld.gravity = CGVectorMake(x, y)
    }
}   

I could map the Y axis which makes the ball go "up" or "down" (relative to portrait mode) however I don't understand how to map the X axis (the pull from the side of the device).

For example, when putting the device flat on the table (x, y) should be (0,0) and when putting it on the table screen-down it should also be (0,0) however attitude.roll returns -179. Also if I keep my device vertical (on portrait mode) and turn on my feet keeping the device still, gravity should remain (x: 0, y: 1) however x continues to change as it's based on attitude.roll

How can this be done?

Was it helpful?

Solution

The most straightforward way would be to take accelerometer updates, not device motion updates, and directly read the gravity vector from there — that's exactly what the accelerometer captures: a measure of gravity in the device's coordinate system.

Sadly I'm a Swift thickie so can't provide example code but you're looking to provide a block of type CMAccelerometerHandler which will receive a CMAccelerationData from which you can obtain CMAcceleration struct and that is, directly, the gravity vector to apply.

if let data = motionManager.accelerometerData? {
    vec = CGVectorMake(CGFloat(data.acceleration.x), CGFloat(data.acceleration.y))
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top