Accelerometer Mysteries

Ok, I feel like I need to establish my math creds before I begin talking about this: I was good at math once. I got an A or A+ in every math class I ever took, including AP Calculus. My problem is, I don’t remember a darn thing from any of those classes, least of all trigonometry.

And as it Turns Out™, there’s some trig involved in making games. :-)

I get how the accelerometer works: it measures the rotation of the x-, y-, and z- axes and returns a value between -1 and 1. I’ve been using a Ray Wenderlich tutorial on the accelerometer to help me figure out how to translate that data into a velocity vector for my game character (I’d link to it, but it’s in their iOS Games book). The tutorial writers, ostensibly pressed for time and/or chapter space, included a handy Swift file full of convenience methods for working with 3D vectors. The only problem with that is it’s making it harder for me to grasp what’s really happening and why. My “move” function for my character feels a little bit like a black box: accelerometer data goes in, a velocity vector comes out, and I’m not really sure what happened in between.

From what I can gather, the reason for working with 3D vectors to begin with is because I need to define a neutral orientation for users to hold their phone. Otherwise, people would have to play my game with their devices held perfectly flat.

To help solve this, the RW team created their own “Vector 3” struct, with x, y, and z properties. There’s a function to determine the magnitude of the vector, which I understand, as well as a couple of functions for normalizing the vector, which I feel like I’m on the verge of understanding. Where it all breaks down for me is two included functions that calculate the “dot product” and “cross product” of two vectors.

I’ve never heard of those mathematical functions, and looking up their definitions hasn’t helped me much. Here’s how they are used in context:

In defining neutral orientation constants:

let ay = Vector3(x: -0.78, y: 0.0, z: -0.61)
    let az = Vector3(x: 0.0, y: -1.0, z: 0.0)
    let ax = Vector3.crossProduct(Vector3(x: 0.0, y: -1.0, z: 0.0), right: Vector3(x: -0.78, y: 0.0, z: -0.61)).normalized()

In translating to a 2D vector:

let rawData = Vector3(x: CGFloat(motionManager.accelerometerData!.acceleration.x), y: CGFloat(motionManager.accelerometerData!.acceleration.y), z: CGFloat(motionManager.accelerometerData!.acceleration.z)) // Raw accelerometer data
        
        acceleration2D.x = Vector3.dotProduct(rawData, right: az)
        acceleration2D.y = Vector3.dotProduct(rawData, right: ax)
        acceleration2D.normalize()

Anyway, all that’s to say that I can use the accelerometer to move my character (without any rotation of the sprite…that’s on my to-do list for tomorrow) and it basically works. I just don’t know why it works. Maybe I don’t need to?

Does anybody else have sections of their own code that they don’t necessarily understand completely? It sounds like bad practice but maybe I can get away with it this time.