I have searched internet and read all the documentation, forums, Unity answers, and blogs I could find in an effort to answer this question myself. 99% of the time that works, but not this time so here we go:
startTiltY is set in Start() to ensure the user can play holding the device at any Y angle. Everything works great if the user holds the device between parallel to the ground to tilted towards them near perpendicular to the ground. If the user is holding the device perpendicular or any other way, then āDo something #1ā and āDo something #2ā wonāt ever be fired depending on which way you are over-tilting.
I am assuming this return value is being capped at a certain point, or wrapping over to the other side of its range.
How can I ensure no matter how the user is holding his/her device my code will still know if the user is tilting to go up or down? Thanks in advance.
Thank you for responding, Polymorphik. I do recall reading a couple of post where this was mentioned but no one has gone into more detail than that from what Iāve found online.
Could you elaborate a bit on how this process works? or if you can supply a link to this answer, I would be very happy with that as well. Thanks again.
Well what you need is to first get the initial orientation of the phone. Based off this orientation we are essentially setting our origin (axis) based on this initial orientation. Rotations are better represented by a matrix.
So step one is to create a baseMatrix to which you will send accelerometer information to compensate for the initial orientation of the device (calibration).
Now call this when the controller is first created like in Start for instance. Now instead of using the Input.acceleration values directly we will multiply it by the baseMatrix (calibration) to get the adjusted input.
public Vector3 AdjustedAccelerometer {
get {
return this.baseMatrix.MultiplyVector(Input.acceleration);
}
}
Now you can use the adjusted value to tilt your device in any orientation such as laying on your side, laying on your back etc. Hope this helps.
I had to convert it to C# and change the old iPhoneInput.acceleration call to Input.acceleration, but it was working very well when I tested the new build.
private Quaternion calibrationQuaternion;
// Used to calibrate the Input.acceleration
void CalibrateAccelerometer()
{
Vector3 accelerationSnapshot = Input.acceleration;
Quaternion rotateQuaternion = Quaternion.FromToRotation(
new Vector3(0.0f, 0.0f, -1.0f), accelerationSnapshot);
calibrationQuaternion = Quaternion.Inverse(rotateQuaternion);
}
void Start()
{
CalibrateAccelerometer();
}
void Update()
{
Vector3 theAcceleration = Input.acceleration;
Vector3 fixedAcceleration = calibrationQuaternion * theAcceleration;
// Use fixedAcceleration for any logic that follows
}
Thank you again, Polymorphik, for helping me get this figured out.
Thank you both for the post. Iāve been searching for ages for a method of calibrating a mobile device so that perpendicular is not zero; rather the playerās preferred position is zero. The movement controls that I have work as desired to move the object other than being calibrated.
If I understand this correctly, you are checking the initial values of the deviceās orientation and storing them. And if the accelerometer changes from those values, you apply code for movement. Pardon my ignorance as I am new to programming.
How do you end up applying fixedAcceleration to your game object? Do you continue to use if / else statements to control based on degree of tilt? For example, if fixedAcceleration > .007 you apply movement forward.
Below is my code:
void FixedUpdate ()
{
float moveHorizontal = Input.acceleration.normalized.x; // left / right movement
float moveVertical = -Input.acceleration.normalized.z; //forward / backwards
// main three directional movement control
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
rigidbody.AddForce(movement * speed * Time.deltaTime);
}
Iām going to try to experiment this evening with the code youāve listed. If you have any suggestions to offer, it would be most appreciated.
Hello, and welcome to the community! Well this will depend on how you want the player to interact with the device. Do you want them to tilt it side to side? or do you want them to tilt towards them and away from the them? Or a mixture of both?
First off yes, you are correct. What needs to happen when you load the controller is it needs to get calibrated via the code I posted. The initial orientation of the device will get stored in a 4x4 matrix since rotations are easily represented by a matrix. We then multiply that baseMatrix by the Input.acceleration in order to get a newly adjusted value where the initial orientation of the device is taken into account.
What I do is I create a ādead zoneā basically any value below this I ignore as input.
Here is a method where I query the accelerometer based on settings defined by the user. You can ignore those but the basic thing to take away from this is the deadZone. Once you get the adjusted accelerometer Vector3 you can now begin to further clean up any garbage input the device might send back. The values generally on all axis are from -1.0 to 1.0 but if you look at the Input.accelerometer that is not always the case. So I adjust the values based on the deadZone (user defined) and I make sure to clamp the values between -1.0 to 1.0 to make sure I donāt get any weird input.
The other part I adjust is the angle. Now by default the angle at which you would need to tilt the device to read -1.0 or 1.0 or the maximum tilt on either direction is 90Āŗ. This can be kinda damaging based on how the game works, if its a racing game then I totally understand but not all games should require you to tilt all the way in order to reach max velocity, again each game is different. So what I do is take the angle and divide it by the maximum tilt angle which is 90Āŗ, this is all done with variables no hardcoded values) I then take that value and divide it into a variable called āvalueā which will get sent back. The switch statement is generic so I can adjust what axis does what for which input (kinda confusing but my accelerometer works for any game not just mine its generic not specific). Lastly I multiply it by some sensitive value and return it. There is invert that will flip the negative sign kinda how joysticks have the invert Y for shooters.
float AccelerometerInput(AccelerometerOrientationSettings oSettings) {
this.input = this.AdjustedAccelerometer;
float value = 0.0f;
switch(oSettings.axis) {
case Axis.XAxis:
value = input.x;
break;
case Axis.YAxis:
value = input.y;
break;
case Axis.ZAxis:
value = input.z;
break;
default:
UnityEngine.Debug.LogWarning(typeof(Accelerometer).ToString() + " - AccelerometerInput(): Axis is not defined! Return 0.0f");
return 0.0f;
}
if(Mathf.Abs(value) < this.settings.DeadZone) {
value = 0.0f;
} else {
if(value > 0.0f) {
value -= this.settings.DeadZone;
} else {
value += this.settings.DeadZone;
}
float trueValue = oSettings.angle / Accelerometer.maxAngle;
value /= trueValue;
value /= (1.0f - this.settings.DeadZone);
}
value = Mathf.Clamp(value, -1.0f, 1.0f);
return value * this.settings.Sensitivity * ((oSettings.invert) ? -1.0f : 1.0f);
}
Anyways based off of these values I recommend you change the velocity of the gameObject instead of adding a push. Changing the velocity can be more responsive than adding forces. Also by adjusting the velocity you can cap the speed with simple Vector math. If you need help implementing an accelerometer let me know and I would be graded to help! I had to learn all of this on my own so I know how hard it can be.
Hi! Thank you to everyone who posted, this is the closest Iāve been to figure this out, but Iām still not there yet.
So I had to reopen this to say that I used this and instead of calibrating to the position of the phone each time the game starts, it is at a slight angle always. Also, the Y direction is inverted, so I have the point the phone toward me to move up, and away from me to move down. Iām using the Rigidbodies AddForce function to rotate the ball in accordance to the calibrated accelerometer. Any ideas?