Xbox-One Analog Thumbstick mapping in Unity C#
![]() |
After spending a few hours and many tries finally figured out how it can work properly in a manner needed. The good thing, I came across was this Controller Test package in Unity which helps you to see the exact mapping of a controller, also it adds up the settings in Editor--> Input Settings. Which apparently Unity also does as soon as you connect Xbox-One (Oculus_GearVR_***).
I will not talk about how Controller Test package works, as its pretty simple to understand and can be found on this link: Controller Test Asset store
This post is just to provide you a virtual joystick in case you want to use it in your project, prior knowledge of Unity UI and C# is expected:
Step 1:
Check your Editor-->Input Settings
This step is important before you start writing your code for any device input. Check if your attached Xbox One controller device has all the Inputs added into the list. If yes, then look for the ones that you want to map.
In this article, I am focusing on only Xbox-One:
1.Oculus_GearVR_LThumbstickX
2.Oculus_GearVR_LThumbstickY
3.Oculus_GearVR_LIndexTrigger
4.Oculus_GearVR_RIndexTrigger
The proper settings in order to get desired results would be
- Oculus_GearVR_LThumbstickX (X-axis )
- Oculus_GearVR_LThumbstickY (Y-axis)
- Gravity 0, Dead 0.5, Sensitivity 1
- Snap and Invert should be unchecked for both.
Step 2:
Make a pretty UI for your virtual joystick, by using any circular image for a base pad and a handler above it which can be rotated in Z-axis to show the angle. I have set up the UI in this way.
![]() |
Screenshot for UI setup - Unity Editor |
Pad is the base of the joystick on which the "Pointer" will be rotating to show the angle. But the "Pointer" should be only able to rotate in reference to a pivot point which is set on the center of the Pad. That's why the hierarchy and the position of the Pointer are important, as it can be seen from the image, Pad--> Pivot--> Bar & Pointer. For further details of the setup, you can also check the Unity project linked.
Step 3:
Attach the "JoyStickController" script to the main JoyStick game object. And the set the properties accordingly.
![]() |
Set enum states for which controller input to use. |
Now, run the scene and you will get an output like this either you use arrow keys left and right, xbox Left thumb stick or Xbox trigger buttons.
![]() |
Output of virtual joystick at different angles. |
Source project:
https://github.com/asemahassan/XboxOneController.git
Complete Code:
public enum JSControllerState { None = -1, Arrow_Keys, XboxOne_AnalogThumbstick, XboxOne_TriggerButtons }
using UnityEngine; using UnityEngine.UI; using System.Collections; public class JoystickController : MonoBehaviour { public JSControllerState _controllerState = JSControllerState.None; /// <summary> /// The user response active can be toggled from any script /// To control the input from user /// </summary> public static bool _userResponseActive = false; /// <summary> /// The user response angle stores the final angle /// that user has pointed at using joystick /// </summary> public static float _userResponseAngle = 0f; private static RectTransform knobTransform = null; [SerializeField] private GameObject pivotHandle = null; [SerializeField] private Text angleValueText = null; [SerializeField] private float stepAmount = 1.0f; private static Vector3 rotationEuler; // Use this for initialization void Start () { if (pivotHandle != null) { knobTransform = pivotHandle.GetComponent<RectTransform> (); } //For testing as its only one class you can set it here to true _userResponseActive = true; } // Update is called once per frame void Update () { if (!_userResponseActive) return; switch (_controllerState) { case JSControllerState.None: { Debug.LogError ("Please select a state from JSControllerState"); #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #endif break; } case JSControllerState.Arrow_Keys: { UseArrowKeys (); LockPlayerResponse (); break; } case JSControllerState.XboxOne_AnalogThumbstick: { UseAnalogStick (); LockPlayerResponse (); break; } case JSControllerState.XboxOne_TriggerButtons: { UseTriggerButtons (); LockPlayerResponse (); break; } default: break; } //If you want to ResetAngle at some point, can call ResetJoyStickAngle() method if (Input.GetKeyUp (KeyCode.R)) { ResetJoyStickAngle (); } } /// <summary> /// Uses the arrow keys. /// When testing in Editor without XboxOne controller can use this method. /// </summary> private void UseArrowKeys () { if (Input.GetKey (KeyCode.LeftArrow)) { rotationEuler += Vector3.forward * stepAmount; } if (Input.GetKey (KeyCode.RightArrow)) { rotationEuler -= Vector3.forward * stepAmount; } knobTransform.transform.rotation = Quaternion.Euler (rotationEuler); float angle = 360 - knobTransform.rotation.eulerAngles.z; if (angleValueText != null) { angleValueText.text = angle.ToString (); } _userResponseAngle = angle; } /// <summary> /// Uses the trigger buttons to set angle in Z. /// Virtual joystick will be updated accordingly /// </summary> private void UseTriggerButtons () { if (Input.GetAxis ("Oculus_GearVR_LIndexTrigger") > 0) { rotationEuler += Vector3.forward * stepAmount; } if (Input.GetAxis ("Oculus_GearVR_RIndexTrigger") > 0) { rotationEuler -= Vector3.forward * stepAmount; } knobTransform.transform.rotation = Quaternion.Euler (rotationEuler); float angle = 360 - knobTransform.rotation.eulerAngles.z; if (angleValueText != null) angleValueText.text = angle.ToString (); _userResponseAngle = angle; } /// <summary> /// Uses the left analoque stick to get the user response angle /// Mostly effective when asking user for directional task /// </summary> private void UseAnalogStick () { /*Input Settings: * Oculus_GearVR_LThumbstickX (X axis )&& Oculus_GearVR_LThumbstickY (Y axis) * Gravity 0, Dead 0.5, Sensitivity 1 * Snap/Invert all should be false */ float x = Input.GetAxis ("Oculus_GearVR_LThumbstickX"); float y = Input.GetAxis ("Oculus_GearVR_LThumbstickY"); if (x != 0.0f || y != 0.0f) { float angle = Mathf.Atan2 (x, y) * Mathf.Rad2Deg; angle = (180.0f - angle); if (angleValueText != null) angleValueText.text = angle.ToString (); _userResponseAngle = angle; // multiplying angle with -1 to show the correct orientation of knob on virtual joystick knobTransform.transform.rotation = Quaternion.Euler (new Vector3 (0, 0, -1 * angle)); } } /// <summary> /// Locks the player response. /// </summary> private void LockPlayerResponse () { #if UNITY_EDITOR if (Input.GetKeyUp (KeyCode.L)) { Debug.Log ("User response angle locked: " + _userResponseAngle); _userResponseActive = false; ResetJoyStickAngle (); } #else if(Input.GetButton("Oculus_GearVR_AButton")) { Debug.Log("User response angle locked: " + _userResponseAngle); _userResponseActive = false; ResetJoyStickAngle(); } #endif } /// <summary> /// Resets the joy stick angle /// Resets the _knobTransform eulerAngles back to zero /// </summary> public static void ResetJoyStickAngle () { rotationEuler = Vector3.zero; Quaternion tempQuat = knobTransform.transform.rotation; tempQuat.eulerAngles = Vector3.zero; knobTransform.transform.rotation = tempQuat; } }