How to make gyroscope based controls useable

I am working on a ball rolling platformer game.

The game plays well (I think) with the WASD control scheme I have set up. I wish to make it a possibility to use the gyroscope on an android phone to play the game but I have a few issues.

  1. It seems almost unresponsive, but at the same time, it seems almost to sensitive.
  2. It’s near impossible to play - maybe it’s a lack of practice, but it’s absurdly difficult.

Things I’ve tried: making the slowing down of the ball use a higher modifier for the force applied then the speeding up of the ball, adjusting the the value I’m multiplying by using in relation to gyroscope.attitude at the beginning (using as a home base - if I relaunch the scene it doesn’t seem to accelerate at all after using this method) .

The apk asks for internet access because it phones home for hiscore management, aside from that it uses only the gyroscope and only unity functions.
A link to download the apk

My code:

if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow) || Input.gyro.attitude.y > (defaultValue.y + reqOffset))
            {
#if  UNITY_ANDROID
                float mobileMod = 1;
                if (rigidbody.velocity.z > 0)
                {
                    mobileMod = 0.7f * Mathf.Abs(Input.gyro.attitude.z);
                }
                else if (rigidbody.velocity.z < 0)
                {
                    mobileMod = 1.0f * Mathf.Abs(Input.gyro.attitude.z);
                }
#else
                float mobileMod = 1f;
#endif
                //Forward
                rigidbody.AddForce(Forward * MoveModifier * mobileMod);
            }
            if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow) || Input.gyro.attitude.x > (defaultValue.x + reqOffset))
            {
#if  UNITY_ANDROID
                float mobileMod = 1;
                if (rigidbody.velocity.x < 0)
                {
                    mobileMod = 0.7f * Mathf.Abs(Input.gyro.attitude.x);
                }
                else if (rigidbody.velocity.x > 0)
                {
                    mobileMod = 1.0f * Mathf.Abs(Input.gyro.attitude.x);
                }
#else
                float mobileMod = 1f;
#endif
                //Right
                rigidbody.AddForce(Right * MoveModifier * mobileMod);
            }
            if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow) || Input.gyro.attitude.y < (defaultValue.y - reqOffset))
            {
#if  UNITY_ANDROID
                float mobileMod = 1;
                if (rigidbody.velocity.z < 0)
                {
                    mobileMod = 0.7f * Mathf.Abs(Input.gyro.attitude.z);
                }
                else if (rigidbody.velocity.z > 0)
                {
                    mobileMod = 1.0f * Mathf.Abs(Input.gyro.attitude.z);
                }
#else
                float mobileMod = 1f;
#endif
                //Backwards
                rigidbody.AddForce(Backwards * MoveModifier * mobileMod);
            }
            if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow) || Input.gyro.attitude.x < (defaultValue.x - reqOffset))
            {
#if  UNITY_ANDROID
                float mobileMod = 1;
                if (rigidbody.velocity.x > 0)
                {
                    mobileMod = 0.7f * Mathf.Abs(Input.gyro.attitude.x);
                }
                else if (rigidbody.velocity.x < 0)
                {
                    mobileMod = 1.0f * Mathf.Abs(Input.gyro.attitude.x);
                }
#else
                float mobileMod = 1f;
#endif
                //Left
                rigidbody.AddForce(Left * MoveModifier * mobileMod);
            }

1 Answer

1

I once did the game like this, also had similar problems, what worked for me was to get only half of the input from gyro into consideration (from 0-0.5, treat 0.5 as maximum) and project it to the board rotation. Than instead of multiplying it by constant, I set a curvefield (evaluated in function of gyro) variable with straight line going from high value to low. So when my gyro move is tiny it will be multiplied by higher value i.e 2 (don’t remember exact value), but than if the gyro is close to 0.5 the value from curve is for instance 0.8. That provides good responsiveness with tiny moves and keep extreme moves under control. You can probably test it using unity remote :slight_smile:

Hope it helps

Edit// setting up ball physic and physical materials for each collision was also an important step.

Unity remote? So, are you talking about this [curve field?][1] [1]: http://docs.unity3d.com/ScriptReference/EditorGUI.CurveField.html

Unity remote lets you play game in editor but control via your device (https://www.assetstore.unity3d.com/en/#!/content/18106) Yes this curve field, there is only one curve field.

So far that has helped a ton small - I'm having one big issue though.. when I begin tilting my phone along what is a single axis two axis values are changing in the attitude variable - is this normal? I have tried with euler angles and limiting the values between 0-10 and 350-360, but even with using euler angles I appear to be having two angles switch at large quantities by just tilting my phone towards and away from me.

Well gyro on the device can be precise, What I did was put some tmp GUI text on the screen and display the X and Y values directly ( at that time didn't know about unity remote). That helped me understand the gyro and input values it gives. Than you can test your assumption by putting phone on the table and lifting just one side.