**Question**by DeOlijus · Oct 06, 2015 at 02:46 AM · c#scripting problemscriptingbasicsscripting beginnerrotate object

# Rotate Player 90 degrees about its Y axis relative to the mouse being dragged between two angles

Hello, I am new to Unity and scripting in general so I am trying to learn as much as I can about different ways to manipulate the way my character moves and rotates. I was playing a game called Crossy Road and I wanted to know how I would rotate my character similarly via C# script.

Basically I want to write a simple script to attach to my game object that rotates my character (up, down, left, right), about the y-axis, when the mouse is dragged between two angles relative to where the mouseDown occurred. I provided a picture that hopefully clarifies what I mean.

I have considered using RaycastHit, Physics.Raycast and SLerp but I am still very confused on how to properly incorporate them together. I am also confused about how to make boundary angles. Does unity go by degrees or is it possible to use radians?

I am sure if I could make my game object at least follow the direction my mouse drag rotates, relative to the click, I could easily use an if statement to clamp the character to rotating 90 degrees once the drag passes a certain amount of degrees. The problem is I am unsure how to clearly obtain the values I need.

I have looked at many different examples and tutorials but nothing I have seen quite captures what I am looking for. I am doing my best to get better at scripting but this seriously has me stumped so of course Any feedback is greatly appreciated!

**Answer** by Statement
·
Oct 10, 2015 at 10:44 PM

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);
}
}
```

Oh I see this makes so much sense now! So the main idea is that you can get the Angle from the arc-tangent of the Input.mousePosition x and y components by taking the relative distance/location of the initial click to where the current drag is on screen. Then lock the rotation of the player to up,down,left,right if the angle falls within a specific region.

I was getting so confused on how I should start and how to properly use certain functions from the scripting API. I really like the idea of having many separate scripts working cleanly together like the way you pieced yours together. That made your answer very clear to understand. I am definitely going to play around with this a lot more and see if I can match it to my gameobject and even add a hopping ability to it!

This was incredibly helpful! Thank you so much @statement I really appreciate your insight.

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.