1
\$\begingroup\$

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.

Image of dial with 0 at the top and 7 increment marks evenly spaced around the rest

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;
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – DMGregory
    Jun 20 at 11:48

1 Answer 1

1
\$\begingroup\$

First, you can simplify your angle method:

public static float DegreesCCWFromRight(Vector2 center, Vector2 pointer) {
    var direction = pointer - center;
    return Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
}

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);
}
\$\endgroup\$
4
  • \$\begingroup\$ 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! \$\endgroup\$ Jun 20 at 16:19
  • \$\begingroup\$ 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? \$\endgroup\$ Jun 20 at 17:51
  • \$\begingroup\$ @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 \$\endgroup\$
    – Zibelas
    Jun 21 at 8:17
  • \$\begingroup\$ I see thanks! Will do this. \$\endgroup\$ Jun 21 at 8:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .