3
\$\begingroup\$

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?

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – congusbongus Apr 8 '14 at 0:34
  • \$\begingroup\$ @congusbongus I'm implementing this now: stackoverflow.com/a/5780505/1991295 Still absolutely no difference. \$\endgroup\$ – async Apr 8 '14 at 17:04
1
\$\begingroup\$

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);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.