2
votes

I have been trying to learn XNA, and while I don't have access to books I've been relying on MSDN and tutorials to guide me along the way and I can now draw sprites and change their position and use Intersect and I am now trying to get a basic Accelerometer going for Windows Phone 7 and 8 phones.

I have some blocks and a ball. And I want to be able to move the ball (or roll it) by just tilting the phone up/down/left/right.

If you see below, the green dots represent areas where the ball can move. While the dark grey blocks are just boundaries where if the ball touches them it will bounce off of them (at a later time, I'm not concerned about this part yet).

My question is, how do I get the ball to respond correctly to tilt movements?

To try and get very basic tilt movements I have:

    protected override void Initialize()
    {
        // TODO: Add your initialization logic here

        Accelerometer accelerometer = new Accelerometer();
        accelerometer.CurrentValueChanged += accelerometer_CurrentValueChanged;
        accelerometer.Start();

        base.Initialize();
    }

    void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
    {

            this.squarePosition.X = (float)e.SensorReading.Acceleration.Z * GraphicsDevice.Viewport.Width + GraphicsDevice.Viewport.Width / 2.0f;

            if (Window.CurrentOrientation == DisplayOrientation.LandscapeLeft)
            {
                this.squarePosition.X = +(float)e.SensorReading.Acceleration.X * GraphicsDevice.Viewport.Width + GraphicsDevice.Viewport.Width / 2;
            }
            else
            {
                this.squarePosition.X = (float)e.SensorReading.Acceleration.X * GraphicsDevice.Viewport.Width + GraphicsDevice.Viewport.Width / 2;
            }
        }

But it's absolutely shocking. It's very jittery, like, the object is constantly jumping around like it's having a seizure or something, and I am not even sure it this is the correct way to go about this.

enter image description here

2
I've never written code for accelerometers, so I won't be able to help you much. Still, something is bothering me: afaik, the accelerometer detects a variation on velocity. So you shouldn't update the position every time the accelerometer value changes: you should, in the XNA Update method, change the position depending on the latest value of the accelerometer. This way, if you inclinate the phone then stop moving, the ball will keep on moving in a smooth motion. Or you could use the gyroscope instead: msdn.microsoft.com/en-us/library/windowsphone/develop/… - Kevin Gosse
Also, you're assigning to squarePosition.X a value read from the Z axis of the accelerometer, then overwriting it with a value read from the X axis. I think one of the two assignments was supposed to be for squarePosition.Y instead - Kevin Gosse

2 Answers

4
votes

The main issue you have is directly linking acceleration to position, instead of using the acceleration to affect a velocity and the velocity to affect the ball's position. You've made it so the position of the ball is how much you tilt, instead of accelerating based on how much you tilt.

Currently, whenever the accelerometer reading changes, the ball's position is set to the reading. You need to assign the ball's acceleration to the reading, and periodically increase a velocity by that acceleration and also periodically increase the ball's position by that velocity.

XNA probably has a built-in way to do this, but I don't know XNA so I can just show you how I would do it without help from a framework/library:

// (XNA probably has a built-in way to handle acceleration.)
// (Doing it manually like this might be informative, but I doubt it's the best way.)
Vector2 ballPosition; // (when the game starts, set this to where the ball should be)
Vector2 ballVelocity;
Vector2 ballAcceleration;

...

void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e) {
    var reading = e.SensorReading.Acceleration;
    // (below may need to be -reading.Z, or even another axis)
    ballAcceleration = new Vector2(reading.Z, 0);
}

// (Call this at a consistent rate. I'm sure XNA has a way to do so.)
void AdvanceGameState(TimeSpan period) {
    var t = period.TotalSeconds;
    ballPosition += ballVelocity * t + ballAcceleration * (t*t/2);
    ballVelocity += ballAcceleration * t;

    this.squarePosition = ballPosition;
}

If you have no idea where that t*t/2 came from, then you will probably want to read up on basic physics. It will help a lot with understanding how to make that ball move the way you want. The relevant bit of physics is called kinematics (videos).

1
votes

You will need to do some kind of smoothing on the input to remove this kind of jitter.

There's a Micrsoft Blog with some information about it here:

http://blogs.windows.com/windows_phone/b/wpdev/archive/2010/09/08/using-the-accelerometer-on-windows-phone-7.aspx

In particular, look at the section entitled A Look at Data Smoothing