Accelerometer

Hi friends!!

I am finalizing details of my first game for Android and I had some doubts.

I am making a game in which the movement is with the accelerometer. The inconvenience is that when I’m on the bus or if the device vibrates (a message arrives), this interferes with the player’s movement. It moves crazy everywhere, and the gaming experience becomes very bad. I need to soften this movement a bit to improve that experience. Any suggestions?

THANKS A LOT!

My script movement.

public class MovimientoPersonaje : MonoBehaviour {

 [SerializeField]
 public float speed = 10f;
 public SpriteRenderer spriteRotar;
 public Rigidbody2D boxDudeRigid;

 public float variablePosicion = 0f;

 MatrixCalibrate calibration;

 public void MovimientoAcelerometro () {

     Vector3 dir = Vector3.zero;
     dir.x = (Mathf.Abs (_InputDir.x) > 0.07f) ? _InputDir.x : 0;

     if(dir.sqrMagnitude > 1)
         dir.Normalize();

     dir*= Time.deltaTime;
     transform.Translate(dir * speed);

     if(_InputDir.x < -0.02){
         spriteRotar.flipX = true;
     } 
     if(_InputDir.x > 0.02){
         spriteRotar.flipX = false;
     }
 }
 //Method for calibration 

 //Method to get the calibrated input 
 Vector3 getAccelerometer(Vector3 accelerator){
     Vector3 accel = this.calibration.calibrationMatrix.MultiplyVector(accelerator);
     return accel;
 }
 //Finally how you get the accelerometer input
 Vector3 _InputDir;

 // Use this for initialization
 void Start () {
     calibration = GameObject.Find ("Calibrate").GetComponent<MatrixCalibrate> ();
 }
 // Update is called once per frame
 void Update () {
     _InputDir = getAccelerometer(Input.acceleration);
     //then in your code you use _InputDir instead of Input.acceleration for example 
     //transform.Translate (_InputDir.x, 0, -_InputDir.z);
     MovimientoAcelerometro ();
 }

}

The accelerometer is not ment to detect the orientation of your device. It’s often used / abused for orientation sensing but it has exactly the issue you’re describing. The accelerometer detects the linear acceleration of the device in each direction. The reason why you can actually use it for orientation sensing is that we have gravity. If you’re not moving the device you have a constant acceleration of 1g downwards. However as soon as you accelerate the device in any other direction the acceleration get mixed with gravity.

Almost all modern mobile devices have a seperate gyroscope. The gyroscope does not detect linear acceleration but angular acceleration and integrates it to get an orientation value. This is (more or less) not affected by any linear motion.

Note that some devices do not have a gyro and others may simulate a gyro using the acceleometer.

Smoothing the accelerometer usually doesn’t help much. It either adds too much latency to the input so it becomes unplayable or it’s not enough and you still get problems with tiny accelerations.

Though if you want to smooth it, the best way would be a PID controller as you can fine tune how much the linear (P), how much the integral (I) and how much the differential (D) component affect the output. You probably want to keep D low or equal to “0”. If you use P = 1 and I = 0 you get no change at all. You want to use something in between, for example P = 0.5 and I = 0.5.

A simple PID controller example has been posted by Andeeeee on the forum

When you use this PID script you can simply declare a public variable of type PID in your script and tweak the values for pFactor, iFactor and dFactor in the inspector.

To use it you would do something like this:

public PID accelerometerPID = new PID(0.5f, 0.5f, 0f);
private float accelerometerCurrent = 0;

    // Inside "MovimientoAcelerometro"
    Vector3 dir = Vector3.zero;
    accelerometerCurrent = accelerometerPID.Update(_InputDir.x, accelerometerCurrent, Time.deltaTime);
    dir.x = (Mathf.Abs (accelerometerCurrent) > 0.07f) ? accelerometerCurrent : 0;

Any Answer?

I have done some work using the accelerometer, I’m not saying buny89’s post was wrong, but here’s another approach that may work for you.

    public float rotationSpeed = 1.85f;
    const float ROTATE_AMOUNT = 2;
    private Quaternion rot;
   
    void OnEnable()
    {
        //used for android input
        rot = transform.rotation;
    }

    void Update()
    {
        float tiltValue = GetTiltValue();
        Vector3 oldAngles = transform.eulerAngles;
        transform.eulerAngles = new Vector3(oldAngles.x, oldAngles.y, 
       oldAngles.z + (tiltValue * ROTATE_AMOUNT));   
    }

    float GetTiltValue()
    {
        const float TILT_MIN = 0.05f;
        const float TILT_MAX = 0.2f;
       
        // Work out magnitude of tilt
        float tilt = Mathf.Abs(Input.acceleration.x);
        
        // If not really tilted don't change anything
        if (tilt < TILT_MIN)
        {
            return 0;
        }

        float tiltScale = (tilt - TILT_MIN) / (TILT_MAX - TILT_MIN);
       
        // Change scale to be negative if accel was negative
        if (Input.acceleration.x < 0)
        {
            return -tiltScale;
        }
        else
        {
            return tiltScale;
        }
    }

I hope this may help.