Rotating object with mouse (658174)

I would like to make something like screwing / unscrewing item with mouse movement. In order to unscrew it I need to make mouse round movements and make one or two rounds. Object is in front of the camera from top view.

Here is detailed version of my goal:
In order to unscrew item, player can’t just move mouse horizontally or vertically. Player has to make a complete round movement (by using Input.GetAxis(“Mouse X”), Input.GetAxis(“Mouse Y”) we can get mouse offset from center, so for example player has to right, right and little down, continue going down, down, down, down and little left and so on). If player keeps going mouse only, for example, right, valve / screw will rotate only a little less than 90 degrees.

Detailed effect I would like to do is here at 4:24

So the question is, how to make such effect? It spent me some time to think about it, but for now I have no idea how to do it even in theory.

Let’s break it down into the parts of the problem.

  1. Detect that the user is “grabbing” the wheel. Easy enough with a raycast
  2. Detect that the user is rotating the mouse around the center.
  3. Apply the appropriate rotation to the model

It seems like #2 is the main thing you need help with, correct?

So while the user is turning the wheel, there are two points that matter: The center of the wheel, and the position of the mouse. It’s easiest on the math if both of these are in screen space, though that will only really look right as long as the player is in front of the wheel, so you may want to enforce that. You can use Camera.main.WorldToScreenPoint(wheelCenter.transform.position) to put that into screen space, and Input.mousePosition will give you the mouse.

So now we have those two positions, it’s time for MATH! We’re actually going to reduce the two positions into one - subtract the wheel center from the mouse position. This is now the position of the mouse, relative to the center. We need to turn this into an angle, and Unity’s math library provides just the thing: Mathf.Atan2(y, x). It does precisely when we need it for here. Note that 1) its parameters are (y, x), in that order; and 2) it output the result in radians, which you probably want to convert to degrees by multiplying by Mathf.Rad2Deg.

So now we have reduced all our numbers to one magic number, the angle. From here it should be a relatively simple matter to rotate the wheel by the same angle. You’ll want to store the result from last frame, and subtract the two angles, so that only the difference is what you rotate the wheel by.

One more issue you’ll have to contend with: at some point in the circle, you’re gonna go from 359.9 to 0. This is a special case to program for, but it’s not too difficult. Since every frame, the player will only turn it by a small number of degrees - less than 180 - we can use that threshold to modify this frame’s angle so that it’s always smoothly proceeding from last frame’s:

while (lastFrameAngle > thisFrameAngle + 180f) {
thisFrameAngle = thisFrameAngle + 360f;
}

You might not notice the issue visually, but assuming you are going to be checking for X turns, this is how you’ll do it.

And that’s pretty much that. If there are any parts of this that need clarification, ask.

1 Like

First of all, thank you for your effort in trying to help me and writing such large message with many handy tips, informations and guides.
I’m not sure, but most likely we misunderstood each other or I have wrongly followed your instructions.

Here is my code I did so far:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ValveRotation : BaseEntity
{
    private Vector2 nextMouseMove;
    private Rigidbody rb;
    private bool clickedOn;
    private Vector2 savedCursorPosition;

#if UNITY_EDITOR
    public override void AddInspectorFields(BaseEntityEditor Editor)
    {

    }

    public override bool DrawDefaultInspector()
    {
        return true;
    }
#endif
    public override EntityType GetEntityType()
    {
        return EntityType.NONE;
    }

    void Start()
    {
        base.Start();
        this.rb = this.GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        base.FixedUpdate();
        if(this.clickedOn)
        {
            if(this.nextMouseMove.x != 0f || this.nextMouseMove.y != 0f)
            {
                float angle = Mathf.Atan2(this.nextMouseMove.y, this.nextMouseMove.x) * Mathf.Rad2Deg;
                Quaternion lastRotation = this.rb.rotation;
                this.rb.rotation *= Quaternion.Euler(new Vector3(angle, 0f, 0f) * Time.fixedDeltaTime);
            }
        }
    }

    void Update()
    {
        base.Update();
        this.nextMouseMove = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));

        if(this.clickedOn && Input.GetMouseButtonUp(0))
        {
            this.clickedOn = false;
            CursorManager.Instance.CursorPosition = this.savedCursorPosition;
            CursorManager.Instance.Visible = true;
        }
    }

    public override void OnGUIMouseButtonDown(int MouseButton)
    {
        if(MouseButton != 0)
        {
            return;
        }
        this.savedCursorPosition = CursorManager.Instance.CursorPosition;
        CursorManager.Instance.Visible = false;
        this.clickedOn = true;
    }
}

Wheel is rotating when I keep moving mouse vertically. If I try same horizontally, sometimes it’s rotating, sometimes not, sometimes switches directions, etc.

But the most important thing is - this is not the effect I was looking for.

The thing I’m looking for is when I click on the wheel I have to simulate mouse round movement - I have to make a round with my hand holding mouse, to make a wheel rotating.

Let’s say when wheel has 0 degrees its facing right side. If I move mouse only left, it would barely change it’s angle, but if I move mouse top, it will start rotating up, similar situation with down. But if it reaches 90 degrees, moving mouse only vertically (top or bottom) will barely give any effect, so I have to start moving mouse horizontally to reach 180 degrees.

As I said, maybe this is what you are trying to tell me, but I misunderstood, if yes, sorry. Anyway I will be glad if you refer to my reply.

Best regards.