3

Take Doodle Jump and other games that rely on the accelerometer. The movement of the character is very smooth and I have no idea how they implemented it. I've seen a number of SO/GameDev/forum questions, but the discussion ends abruptly when someone recommends a high/low pass filter. I've tried that (unless I'm missing something) and the results are nowhere near smooth.

All I'm trying to do is move a character on the x axis. This is the code I have and it's very "choppy". It's actually the code you can see on the official Android tutorials.

float alpha = 0.9f; //tried many values from 0.1f to 0.99f. chopiness still there

@Override
public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        if(init) {
            gravity[0] = event.values[0];
            gravity[1] = event.values[1];
            gravity[2] = event.values[2];

            init = false;
        } else {
            gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
            gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
            gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
        }

        // Remove the gravity contribution with the high-pass filter.
        linear_acceleration[0] = event.values[0] - gravity[0];
        linear_acceleration[1] = event.values[1] - gravity[1];
        linear_acceleration[2] = event.values[2] - gravity[2];

        character.setX(character.getX() - linear_acceleration[0]);

    }

I also tried multiplying linear_acceleration[0] with a sensitivity, where 0 < sensitivity < 1 but the choppiness still doesn't go away. What is the next step from here to achieve a smooth movement like in Doodle Jump?

async
  • 745
  • 1
  • 7
  • 23
  • It's not "high/low pass filters" that remove choppiness. It's low pass filters specifically. What you have is a high pass filter, which does not remove choppiness. – congusbongus Apr 08 '14 at 00:34
  • @congusbongus I'm implementing this now: http://stackoverflow.com/a/5780505/1991295 Still absolutely no difference. – async Apr 08 '14 at 17:04

1 Answers1

1

OK, I managed to sort this out and it was a bit stupid. Yes, the low-pass filter DOES solve the problem. Actually here's my code (note I'm doing it in a different method, but just copy and paste the contents in onSensorChanged(SensorEvent) if you wish:

private static final float alpha = 0.65f;
private static final float SENSITIVITY = 1f/128;
private boolean firstTime = true;

@Override
public void handleSensorEvent(SensorEvent event) {
    if(firstTime) {
        vals[0] = event.values[0];
        vals[1] = event.values[1];
        vals[2] = event.values[2];
    }

    vals[0] = vals[0] + alpha * (event.values[0] - vals[0]);
    vals[1] = vals[1] + alpha * (event.values[1] - vals[1]);
    vals[2] = vals[2] + alpha * (event.values[2] - vals[2]);

    character.setX( character.getX() - vals[0] * SENSITIVITY );
}

You can calibrate alpha and SENSITIVITY according to your needs. Now this is why this code was producing very choppy movement initially: in my activity's onResume() I was registering my listener using SensorEvent.SENSOR_DELAY_NORMAL. That is wrong. What you have to do is register it with SensorEvent.SENSOR_DELAY_GAME. I think the reason behind this is obvious. So in your activity's onResume():

sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);

where accelerometer is declared as (in onCreate()):

accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
async
  • 745
  • 1
  • 7
  • 23