0
\$\begingroup\$

I have 4 dials that rotate by increments when the players drag them. They all exactly have the same code, but I can't figure out why only one of the dial works as intended (dial 2). My code stops working as intended on other dials when I change the increment count to 4, the other dials rotate a quarter and then stops to move when I drag them.

Dials need to be rotated by increments (quarter of a circle)

Here's my class attached to the dial.

public class Rotate2d : MonoBehaviour
{
    float previousRotation;
    float currentRotation;

    void Update()
    {
        RotateObject();
    }

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

    //v2 rotate with incremental snapping
    private void RotateObject()
    {
        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>())
            {
                previousRotation = DegreesCCWFromRight(transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition));
            }
        }

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

                Vector2 mouseWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                float angle = DegreesCCWFromRight(transform.position, mouseWorld);

                const float incrementCount = 4;

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

                hit.collider.gameObject.transform.localEulerAngles = new Vector3(0, 0, angle);

            }
        }

Here's my Project Hierarchy
enter image description here

Here's each dials inspector
enter image description here

enter image description here

enter image description here

enter image description here

\$\endgroup\$
5
  • \$\begingroup\$ I've noted two things but I don't know if they will be any help or not: DegreesCCWFromRight should not be static, I think. Using atan2 (multiplied by rad2deg) will give back an angle between (-180, 180), not (0, 360) (I'm not sure if you already knew this or not so I thought mentioning it is good) \$\endgroup\$
    – Arian_ki
    Jun 21 at 17:08
  • \$\begingroup\$ @Arian_ki why should it not be static? What instance members do you believe it depends on? \$\endgroup\$
    – DMGregory
    Jun 21 at 18:05
  • \$\begingroup\$ @DMGregory I think it would make problems if you drag your mouse from one dial to another one, but as I said in my comment, I'm not sure \$\endgroup\$
    – Arian_ki
    Jun 21 at 21:09
  • \$\begingroup\$ It seems removing hit.collider.gameObject and just using transform.localEulerAngles in the method works, however it rotates other dials upon the start of rotation. \$\endgroup\$ Jun 22 at 6:51
  • \$\begingroup\$ @Arian_ki that is not what the static keyword means. If you're unclear on what this syntax does, you should consider writing a test to find out before offering potentially misleading advice. \$\endgroup\$
    – DMGregory
    2 days ago

1 Answer 1

1
\$\begingroup\$

The problem is that each Rotate2d has its own independent life cycle, which means that Update will be executed 4 times per frame. If the mouse points to any dial, the four scripts will trigger the corresponding logic.

fix: Determine whether the hit target is the dial itself.

public class Rotate2d : MonoBehaviour
{
    float previousRotation;
    float currentRotation;

    void Update()
    {
        RotateObject();
    }

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

    //v2 rotate with incremental snapping
    private void RotateObject()
    {
        Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector3.forward);

        if (!hit.collider)
        {
            return;
        }
        var hitRotate2d = hit.collider.GetComponent<Rotate2d>();
        if (hitRotate2d != this)
        {
            return;
        }

        if (Input.GetMouseButtonDown(0))
        {
            previousRotation = DegreesCCWFromRight(transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition));
        }
        else if (Input.GetMouseButton(0))
        {
            currentRotation = DegreesCCWFromRight(transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition));
            previousRotation = currentRotation;

            Vector2 mouseWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            float angle = DegreesCCWFromRight(transform.position, mouseWorld);

            const float incrementCount = 4;

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

            hit.collider.gameObject.transform.localEulerAngles = new Vector3(0, 0, angle);
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ a simple If solved it! thanks for this! \$\endgroup\$ 2 days ago

You must log in to answer this question.

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