Rotate a 2D wheel toward the mouse

So I’ve been playing with this for several weeks and I’ve tried several iterations of code and some have gotten me close, but not exactly where I want to be.

Basically, I am trying to rotate a wheel, in 2D space, in a circle toward the direction of where the mouse is currently located at. I think the place where I am getting stuck is how to make the rotation actually occur correctly. As it is currently, when the mouse is pressed on the object I record the location of the click. Then as I drag the mouse around I record the location of the mouse.

I’ve tried getting the angle and setting Euler, getting the angle and use RotateAround, using LookRotation, and FromToRotation. The closest I’ve come is with FromToRotation which I’ll post below. LookRotation works correctly for the rotation, but it flips the object so it is parallel to the z-axis and I need it to stay perpendicular to the z-axis.

I have been trying to get this to work for several weeks and I know this isn’t impossible, I just can’t figure out how to get it to work. Any help would be greatly appreciated!!! See below for examples.

Here is what I am trying to accomplish in a simple diagram:

Here is the FromToRotation code, that works pretty well, except that I have to drag in a really large out circle in order to get it to rotate correctly.

using UnityEngine;

public class SpinWithMouse : MonoBehaviour
{
    public Transform target;
    public float speed = 1f;

    Transform mTrans;
    Vector3 currentLoc;
    public float angle = 0f;

    void Start ()
    {
        //Set the transform for the script to the transform of the object the script is attached to
       mTrans = transform;
    }

    void OnPress()
    {
       //Set the x,y,z that is currently clicked or touched
       currentLoc = UICamera.currentTouch.pos;
    }

    void OnDrag (Vector2 delta)
    {
        //Set the x,y,z of where the mouse is currently at
       Vector3 newLoc = UICamera.currentTouch.pos;

        //Get the difference between the start angle and the stop angle
       //Quaternion targetRotation = Quaternion.LookRotation(newLoc - currentLoc);

        //Set the rotation of the object based on where the click occured and where the mouse is dragged i
        mTrans.localRotation =  Quaternion.FromToRotation(currentLoc,newLoc); //Quaternion.Euler(0f, 0f, -0.5f * delta.x * speed) * mTrans.localRotation;

       Debug.Log("Position " + UICamera.currentTouch.pos);
       Debug.Log("Wheel location " + mTrans.localRotation);
    }
}

Then this is LookRotation Code which gets the rotation perfectly, but it transforms the object so it’s no longer laying flat and thus defeats what I am trying to accomplish.

using UnityEngine;

public class SpinWithMouse : MonoBehaviour
{
    public Transform target;
    public float speed = 1f;

    Transform mTrans;
    Vector3 currentLoc;
	Vector3 startTouch;
    public float angle = 0f;

    void Start ()
    {
        //Set the transform for the script to the transform of the object the script is attached to
       	mTrans = transform;
    }

    void OnPress()
    {
       	//Set the x,ythat is currently clicked or touched
		currentLoc = UICamera.currentTouch.pos;
		
		//Set the distance of the touch from the object
		startTouch = currentLoc - mTrans.localPosition;
    }

    void OnDrag (Vector2 delta)
    {
        //Set the x,y of where the mouse is currently at
       	Vector3 newLoc = UICamera.currentTouch.pos;
		
		Vector3 currentTouch = newLoc - mTrans.localPosition;

        //Get the difference between the start angle and the stop angle
       	//Quaternion targetRotation = Quaternion.LookRotation(newLoc - currentLoc);

        //Set the rotation of the object based on where the click occured and where the mouse is dragged i
        Quaternion newRotation = Quaternion.LookRotation(newLoc - currentLoc); //Quaternion.FromToRotation(startTouch,currentTouch); //Quaternion.Euler(0f, 0f, -0.5f * delta.x * speed) * mTrans.localRotation;
		
		mTrans.localRotation = newRotation;

       	Debug.Log("Position " + UICamera.currentTouch.pos);
       	Debug.Log("Wheel location " + mTrans.localRotation);
    }
}

This is my code trying to use angles, but it just rotates out of control with no seeming ryhm or reason.

using UnityEngine;

public class SpinWithMouse : MonoBehaviour
{
    public Transform target;
    public float speed = 1f;

    Transform mTrans;
    Vector3 currentLoc;
	Vector3 startTouch;
    public float angle = 0f;

    void Start ()
    {
        //Set the transform for the script to the transform of the object the script is attached to
       	mTrans = transform;
    }

    void OnPress()
    {
       	//Set the x,y that is first clicked or touched
		currentLoc = UICamera.currentTouch.pos;
		
		//Set the distance of the first touch from the object
		startTouch = currentLoc - mTrans.localPosition;
    }

    void OnDrag (Vector2 delta)
    {
        //Set the x,y of where the mouse or touch is currently at
       	Vector3 newLoc = UICamera.currentTouch.pos;
		
		//Set the distance of the current touch from the object
		Vector3 currentTouch = newLoc - mTrans.localPosition;

        //Get the Angle between the starting location and the current location
		float angle = Vector3.Angle(newLoc, currentLoc);
		
        //Set the rotation of the object based on where the click occured and where the mouse is dragged i
        //Quaternion newRotation = Quaternion.LookRotation(newLoc - currentLoc); //Quaternion.FromToRotation(startTouch,currentTouch); //Quaternion.Euler(0f, 0f, -0.5f * delta.x * speed) * mTrans.localRotation;
		
		mTrans.RotateAround(transform.forward, angle);

       	Debug.Log("Position " + UICamera.currentTouch.pos);
       	Debug.Log("Wheel location " + mTrans.localRotation);
    }
}

Is this a difficult problem to solve or am I just not approaching this in the right way? It’s my first post on the forums here but I’ve been all over the Answers site and another forum to no avail.

What happens if you restrict the rotation of the wheel to only the one axis that you want it to rotate around? I mean actually go in to the object and in the inspector restrict the axis of rotation…You should be able to use the code that you think almost works then.

If you are referring to the first set of code I’m not sure exactly what you mean since the problem doesn’t seem to be with the other axis of rotation. What the problem appears to be in the code is that the point it is trying to rotate around is the first click point rather than the pivot point of the circle, but I’m not sure why that is.

If it helps here are how each of the sections of code actually run:

Code1
Code2
Code3

I think he meant that you should use the LookRotation code since its work best but then use the lock rotation axis feature to lock the axis of the game object so that it won’t transform into something that you didn’t want.

Well, that kind of get’s it closer, but once I lock the x,y position it messes with the rotation and makes it not rotate correctly at all except for about the first 90 degrees.

using UnityEngine;

public class SpinWithMouse : MonoBehaviour
{
    public Transform target;
    public float speed = 1f;

    Transform mTrans;
    Vector3 currentLoc;
    Vector3 startTouch;
    public float angle = 0f;

    void Start ()
    {
        //Set the transform for the script to the transform of the object the script is attached to
        mTrans = transform;
    }

    void OnPress()
    {
        //Set the x,ythat is currently clicked or touched
        currentLoc = UICamera.currentTouch.pos;

        //Set the distance of the touch from the object
        startTouch = currentLoc - mTrans.localPosition;
    }

    void OnDrag (Vector2 delta)
    {
        //Set the x,y of where the mouse is currently at
        Vector3 newLoc = UICamera.currentTouch.pos;

        Vector3 currentTouch = newLoc - mTrans.localPosition;

        //Set the rotation of the object based on where the click occured and where the mouse is dragged i
        Quaternion newRotation = Quaternion.LookRotation(newLoc - currentLoc); 

		newRotation.y = 0;
		newRotation.x = 0;
        mTrans.localRotation = newRotation;
    }
}

Code4

I don’t really remember this because I’m currently on break from game development., but if I’m not mistaken the current.touch will get x,y, and z component as well. So what must you do is normalize z value, make it the value of where your wheel is located in the z axis. That is if the camera orientation is normal I.e. looking forward at the z-axis. What I mean is when you’re getting the clicks location, it’ll be like 20, 12, 135. So you should change it into 20, 12, (insert the relevant value here)

I tried doing newLoc.Normalize() and currentLoc.Normalize() but then it just rotated even less. Then I tried to just normalize the newLoc but it kept the wheel from moving at all.

Do I need to normalize after the rotation is set and if so, how do I normalize it since it is a Quaternion instead of a vector?

So still at a loss with this.

One other question, is it possible, since the LookRotation rotation works perfectly and it just transforms the gameobject so the axis’s are facing the wrong direction, that I can transcribe the rotation values to a new Quaternion as the correctly axis rotation and then keep the object from transforming, or is that just crazy?

Where are all the rotation experts out there? This seems like a relatively common application of rotation and I know I just must not be grasping something.

If I were you, I’ll use vector.angle(center point of the circle, location of the cursor) to detect the angle, and then, using the value I’ll use the transform.rotate to rotate the circle. Looks like this is the simplest way, but I never had chance to try it myself though.

using UnityEngine;

public class Angle : MonoBehaviour {

public Vector3 target = new Vector3 (1.0f,0.0f,0.0f);
private Vector3 current = new Vector3(0.0f,1.0f,0.0f);
private Vector3 rotation = new Vector3(0.0f,1.0f,0.0f);
public float angle; //So you can see what dot product does

// Update is called once per frame
void Update () {
//Vector3 up is a ray pointing straight up (zero y rotation) and angle is the difference between it and the “current” direction
//Note - you will need to figure out how to translate this to a 360 rotation on your own :wink: it’s easy and there are many ways…

angle = Vector3.Angle(Vector3.up, Vector3.Normalize(current)); //normalizing the current vector is necessary for the comparison
target = new Vector3(target.x, target.y, 0.0f); // Locking z to zero so it’s an xy position only
current = Vector3.Lerp(current, target, Time.deltaTime); //Moving the red line to point at the blue one

Debug.DrawLine(Vector3.zero, Vector3.Normalize(current), Color.red); //current angle
Debug.DrawLine(Vector3.zero, Vector3.up, Color.green); //up (0 angle) marker
Debug.DrawLine(Vector3.zero, target, Color.blue); //target
}
}