Achieve framerate independent AddTorque rotaion with mouse drag.

private float _rotationInput;

void Update()
{
	// Cache delta movement while dragging.
	if(Input.GetMouseButton(0))
		_rotationInput = Input.GetAxis("Mouse X");
	else
		_rotationInput = 0f;
}

void FixedUpdate()
{
	_rigidbody.AddTorque(_rotationInput, ForceMode2D.Force);
}

I am adding physics rotation to a Rigidbody2D by dragging with the mouse. This works the way I want it to, but only for a specific framerate.

My problem: The higher my framerate grows, the slower my rigidbody rotation torque acceleration becomes. Although it is stated, that GetAxis for mouse movement is framerate independent, it gives totally different values.

I’m looking at the Debug.Log statement of my _rotationInput and at a framerate of 30 it gives me values between -5 to 5 when slowly dragging, but at a framerate of 120 it shrinks down to -0.5 to 0.5.

I’m testing in the editor by disabling VSync and setting the targetFrameRate, which seems to work fine, since I’m measuring fps with the tool from Standard Assets, which usually is pretty accurate.

Since the GetAxis is most likely not to change soon, is there a way I can circumvent my problem? Of course, I’ve tried multiplying or dividing by Time.deltaTime in Update or applying the different deltaTimes in FixedUpdate etc, but the effect was always the same, just reversing whether higher framerate becomes a higher or lower delta movement.

Thanks for any ideas!

PS: I know that I wont get a fixed speed by using AddTorque and I will limit the max speed and such things, but the input directly affects the acceleration of the physics rotation, which feels quite different for the player.

You can reproduce GetAxis by simply saving the previous position and subtracting. But I assume this is what GetAxis is doing. The trick is automatically sort-of frame-rate independent. If you drag your finger X amount, the sum over all frames adds to X.

I’m also not sure this is the right way to add spin to an object. Seems like the rate of change each frame (so, divided by deltaTime to normalize) should be compared to the current spin speed. Otherwise a slow drag will send it spinning as much as a fast one.

First, Input.GetAxis values are meant to be used in Update since they correct for the frame rate. You need to be careful using them FixedUpdate as this correction is the opposite of what you need. In this case, it seems like you are using mouse delta (change in cursor position) which will be smaller the faster it is updated. I can think of three possible solutions.

1 Apply the torque in the Update function.

void Update(){
    if(Input.GetMouseButton(0)){
         _rigidbody.AddTorque(_rotationInput, ForceMode2D.Force);
    }
}

2 Cache the input since the last Fixed Update instead of the last Update

private float _rotationInput;
 
void Update()
{
     // Cache delta movement while dragging.
    if(Input.GetMouseButton(0))
        _rotationInput += Input.GetAxis("Mouse X");
    else
        _rotationInput = 0f;
}
 
void FixedUpdate()
{
    _rigidbody.AddTorque(_rotationInput, ForceMode2D.Force);
    _rotationInput = 0f;
}

3 Use unprocessed inputs using Input.mousePosition instead of Input.GetAxis

private bool mouseDown=false;
private float oldPosition;
     
void Update()
{
    if(Input.GetMouseButton(0)){
         if(!mouseDown){
             oldPosition=Input.mousePosition.x;
             mouseDown=true;
         }         
    }
    else{
        mouseDown=false;
    }
}
 
void FixedUpdate()
{
    _rigidbody.AddTorque(Input.mousePosition.x-oldPosition, ForceMode2D.Force);
    oldPosition=Input.mousePosition.x;
}