# How to implement a dial control that snaps to increments?

How can I implement snapping via code? I have this 2d circle that the players rotate via drag and it works like a rotating dial. The best way to describe what I wanted to achieve is similar to a clock hand snapping to the hour numbers. I'm a total beginner and haven't actually learned anything about quaternions.

This is the my code , im using a raycast to detect if the dial is clicked/dragged.

Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector3.forward);

if (Input.GetMouseButtonDown(0))
{
if (hit.collider && hit.collider.GetComponent<Rotate2d>())
{
deltaRotation = 0f;
previousRotation = angleBetweenPoints(transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition));
}
}

else if (Input.GetMouseButton(0))
{
if (hit.collider && hit.collider.GetComponent<Rotate2d>())
{
currentRotation = angleBetweenPoints(transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition));
deltaRotation = Mathf.DeltaAngle(currentRotation, previousRotation);

if (Mathf.Abs(deltaRotation) > deltaLimit)
{
deltaRotation = deltaLimit * Mathf.Sign(deltaRotation);
}

previousRotation = currentRotation;
hit.collider.gameObject.transform.Rotate(Vector3.back * Time.deltaTime, deltaRotation);

}
}


I forgot to add, here is my angle between points method.

   float angleBetweenPoints(Vector2 position1, Vector2 position2)
{
Vector2 fromLine = position2 - position1;
Vector2 toLine = new Vector2(1, 0);

float angle = Vector2.Angle(fromLine, toLine);

Vector3 cross = Vector3.Cross(fromLine, toLine);

// did we wrap around?
if (cross.z > 0)
{
angle = 360f - angle;
}

return angle;
}

• hit.collider.gameObject.transform.Rotate(Vector3.back * Time.deltaTime it's not meaningful to multiply a direction vector by time here. You do not want time in this expression at all. Jun 20 at 11:48

First, you can simplify your angle method:

public static float DegreesCCWFromRight(Vector2 center, Vector2 pointer) {
var direction = pointer - center;
}


Then just round the result to your desired number of increments.

if (hit.collider && hit.collider.GetComponent<Rotate2d>())
{
Vector2 mouseWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
float angle = DegreesCCWFromRight(transform.position, mouseWorld);

const float incrementCount = 6;

angle = Mathf.Round(currentRotation * incrementCount/360)
* 360/incrementCount;

transform.localEulerAngles = new Vector3(0, 0, angle);
}

• Thanks a lot! Finally got it to work! You made it look easy. Will probably spent sometime in the weekend learning some of those math functions! Jun 20 at 16:19
• By the way I managed to make it work but somehow I can't figure out something. I changed the increments to 4/8 since this works perfectly and I wanted it to rotate by quarters or half a quarter. It works on one dial, but when I try to rotate the other dials, it rotates by a quarter and stops totally. What am I doing wrong? Jun 20 at 17:51
• @PeytonFarquhar you can always ask a new question with the updated code that is causing problems (and post the working solution for other amounts). It can be as simple as forgetting to change one variable, having a wrong cast or a simple typo. But when saying works on one and not the others, without showing us whats the difference between your dials, we can't help Jun 21 at 8:17
• I see thanks! Will do this. Jun 21 at 8:45