Accelerometer based games smoothness

| | August 11, 2015

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?

One Response to “Accelerometer based games smoothness”

  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);
    

Leave a Reply