- Home /
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 ();
}
}
Answer by Bunny83 · Sep 17, 2017 at 09:33 AM
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;
Thanks for the explanation, it really is very useful.
But I'm having trouble integrating PID into my code. Basically I have two problems. 1) I can not declare PID, Unity generates error, does not recognize "PID" in:
public PID accelerometerPID = new PID(0.5f, 0.5f, 0f);
2) I do not know what to replace in my code, for the part that you put me. Could you integrate the code in more detail?
$$anonymous$$any thanks. I really appreciate your help.!!!
Uhm, have you actually downloaded the PID controller that Andeeeee wrote? Of course you have to copy that script into your project.
About how to integrate it, i already posted all the changes you need in your script. Of course the two variables are defined in your class next to your other variables and the 3 lines of code i posted should replace the first two lines in your "$$anonymous$$ovimientoAcelerometro" method.
Works!! Thanks a looooooooooooooooooooooooooooooooooooooot!
Answer by Animatick · Sep 18, 2017 at 09:46 AM
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.