You can use Mathf.Atan2 to get an angle from a direction vector - that would be the *red line* or *X* in your graphic. You can get the direction vector by subtracting the mouse position from the position where it was first clicked.

Mathf.Atan2 return a value between -PI and PI, so to get it to map to your graphic, a conversation has to be applied. From there it is just a matter of mapping the angle to predefined angles, something that can be called quantizing the value.

When you have your quantized angle, you can then build a quaternion from Quaternion.Euler for use with transforms. Quaternion.RotateTowards can be used to give a smooth transition from one rotation to another.

Today is my being bored day, so I wrote you a complete example and built a demo.

**CrossyRoadInput.cs**

```
using UnityEngine;
using UnityEngine.UI;
public class CrossyRoadInput : MonoBehaviour
{
public float rotationSpeed = 360f;
public float deadzone = 27f;
public bool centerUnderMouse = true;
public Transform dial;
public Text indexText;
public Text radianText;
public Text degreeText;
private Vector3 mouseCenter;
private Vector2 mouseDrag;
private Quaternion rotation;
void Update()
{
if (Input.GetMouseButtonDown(0))
CenterUnderMouse();
if (Input.GetMouseButton(0))
CalculateDragAndRotation();
RotateDial();
UpdateText();
}
void CalculateDragAndRotation()
{
mouseDrag = Input.mousePosition - mouseCenter;
if (mouseDrag.magnitude > deadzone)
rotation = CrossyRoadMath.QuantizedQuaternionZ(mouseDrag);
}
void CenterUnderMouse()
{
mouseCenter = Input.mousePosition;
if (!centerUnderMouse)
return;
// Move the UI under mouse...
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Plane plane = new Plane(-Vector3.forward, Vector3.zero);
float rayDistance = 0f;
if (plane.Raycast(ray, out rayDistance))
transform.position = ray.GetPoint(rayDistance);
}
void RotateDial()
{
dial.rotation = Quaternion.RotateTowards(dial.rotation, rotation,
rotationSpeed * Time.deltaTime);
}
void UpdateText()
{
if (indexText)
indexText.text = "Index: " +
CrossyRoadMath.QuantizedIndex(mouseDrag);
if (radianText)
radianText.text = "Radians: " +
CrossyRoadMath.QuantizedRadians(mouseDrag).ToString("F2");
if (degreeText)
degreeText.text = "Degrees: " +
CrossyRoadMath.QuantizedDegrees(mouseDrag).ToString("F2");
}
}
```

**CrossyRoadMath.cs**

```
using UnityEngine;
public static class CrossyRoadMath
{
public static Quaternion QuantizedQuaternionX(Vector2 delta)
{
return Quaternion.Euler(QuantizedDegrees(delta), 0, 0);
}
public static Quaternion QuantizedQuaternionY(Vector2 delta)
{
return Quaternion.Euler(0, QuantizedDegrees(delta), 0);
}
public static Quaternion QuantizedQuaternionZ(Vector2 delta)
{
return Quaternion.Euler(0, 0, QuantizedDegrees(delta));
}
public static float QuantizedDegrees(Vector2 delta)
{
return QuantizedRadians(delta) * Mathf.Rad2Deg;
}
public static float QuantizedRadians(Vector2 delta)
{
return Quantize(RadiansFrom(delta));
}
public static float Quantize(float radians)
{
if (radians < Radians.Degree45) return Radians.Right;
else if (radians < Radians.Degree135) return Radians.Up;
else if (radians < Radians.Degree225) return Radians.Left;
else if (radians < Radians.Degree315) return Radians.Down;
else return Radians.Right;
}
// Utility if you need to get 0, 1, 2, or 3 for rotation index mapping.
// Specialized helper that I don't know if you'll need.
public static int QuantizedIndex(Vector2 delta)
{
return QuantizedIndex(RadiansFrom(delta));
}
// Utility if you need to get 0, 1, 2, or 3 for rotation index mapping.
// Specialized helper that I don't know if you'll need.
public static int QuantizedIndex(float radians)
{
if (radians < Radians.Degree45) return 0;
else if (radians < Radians.Degree135) return 1;
else if (radians < Radians.Degree225) return 2;
else if (radians < Radians.Degree315) return 3;
else return 0;
}
public static float RadiansFrom(Vector2 delta)
{
float radians = Mathf.Atan2(delta.y, delta.x);
// At > 3.14 rad, Mathf.Atan2 returns -3.14 rad which shrinks
// back to -0 rad toward 360 deg. To make it easier to think
// in radians, I am converting that range [-PI, 0] so the output
// will be in the range [0, 2PI].
if (radians < 0)
radians = Mathf.PI * 2 + radians;
return radians;
}
}
```

**Radians.cs**

```
using UnityEngine;
public static class Radians
{
public const float Right = 0;
public const float Up = Mathf.PI / 2;
public const float Left = Mathf.PI;
public const float Down = 3 * Mathf.PI / 2;
public const float Degree45 = 1 * Mathf.PI / 4f;
public const float Degree135 = 3 * Mathf.PI / 4f;
public const float Degree225 = 5 * Mathf.PI / 4f;
public const float Degree315 = 7 * Mathf.PI / 4f;
}
```

And for sake of completeness, I provide an alternative, slimmed down version of the script with less UI and functions to get to the core usage.

**CrossyRoadInputSlimmed.cs**

```
using UnityEngine;
public class CrossyRoadInputSlimmed : MonoBehaviour
{
public float rotationSpeed = 360f;
public float deadzone = 27f;
public Transform dial;
private Vector3 mouseCenter;
private Quaternion rotation;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
mouseCenter = Input.mousePosition;
PositionSelfUnderMouse();
}
if (Input.GetMouseButton(0))
{
Vector2 mouseDrag = Input.mousePosition - mouseCenter;
if (mouseDrag.magnitude > deadzone)
rotation = CrossyRoadMath.QuantizedQuaternionZ(mouseDrag);
}
dial.rotation = Quaternion.RotateTowards(dial.rotation, rotation,
rotationSpeed * Time.deltaTime);
}
void PositionSelfUnderMouse()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Plane plane = new Plane(-Vector3.forward, Vector3.zero);
float rayDistance = 0f;
if (plane.Raycast(ray, out rayDistance))
transform.position = ray.GetPoint(rayDistance);
}
}
```