Camera orbiting bug,Camera orbiting bug.

Orbiting around the player works, but if I get my cursor to a different location, it just jumps so that new rotation.

link: Screen capture - d8a7d148e65e8a8d9a8d7c51634257ed - Gyazo

How could I fix this?
this is the script

using UnityEngine;

public class CameraFollow : MonoBehaviour {

GameObject player;
public float speedH;
private float yaw = 0.0f;

void Update()
	yaw += speedH * Input.GetAxis("Mouse X");
	if (Input.GetMouseButton(2))
		transform.eulerAngles = new Vector3(0.0f, yaw, 0.0f);

@PuzzleFoxy, So if I understand correctly, your sense is that when the cursor is near the character, which is in the center of the display, rotation moves at a reasonable speed, but when moving toward the edges of the display it seems to rotate the camera too fast.

This observation is likely associated with the fact that when the cursor is restricted to the middle region of the display your tendency is to move the mouse according to your sense of the character, but as you move toward the edge the tendency is to move the mouse at a faster rate. At the risk of insulting with a version of “this is all in your head”, this may be just you doing this, but it could be associated with settings of the mouse on your computer. Mouse acceleration is a known issue that “gets in the way” of gaming in the way you describe, and the more advanced mouse driver interfaces have “gaming mode” adjustments exactly for this kind of thing. If you temporarily turn off acceleration you might discover there is no bug. If that turns out to be true, the adjustment I discuss next would actually be a problem for users with mice that don’t accelerate.

Now I’ll set aside that potential cause and focus on the code and a potential solution, as this comes up in a variety of controls. Controls are typically linear (with the exception of mouse acceleration, which is somewhat unique). However, humans don’t always prefer linear controls without realizing what that actually is. I find this with joystick controls in the context of microcontrollers operating robotic devices (entirely outside Unity). On a joystick, there is a deadzone, a few ticks of position count that should be ignored because the mechanics of the joystick don’t always return the center as coordinate 0, 0, but slightly off, maybe as much as 5 units off zero. Beyond the deadzone, however, another issue comes forward where users, without conscious realization of it, tend to “need” the region of the joystick near the center to have a different ratio of reaction to that of the extremes. That is, near the center within about 25 degrees or so, they need the joystick to permit precise control of steering or speed, but beyond that range they need the stick to react quickly to large swings of the control.

While joysticks have little in common with mice or touch interfaces, perhaps your situation is similar (though reversed) where you need a “curved” control, not a linear control, where the out regions are “slower” than the interior regions. If speedH in your code has not been sufficient to tame this issue (and, remember, I’m dispensing here with the possibility that mouse acceleration is the problem), what you want is to interpret mouse coordinate output based on where the cursor is.

I doubt that really make sense, because the cursor of the mouse should likely be disabled when rotating the camera (the pointer has nothing to do with camera rotation). Indeed, if you think about it, the actual position of the mouse shouldn’t even be part of the rotation, and should really not be “absolute” (even when scaled by speedH) relative to the position of the mouse cursor. That is to say, yaw would be better served if it were incremented (or decremented as the case may be) by the relative movement of the mouse, not the position of the mouse.

This brings me to two possible suggestions, and a third that is a combination of the two.

First, the yaw value should be increment by the relative position of the mouse. This is not the current output of a call to “Input.GetAxis(“Mouse X”)”, but of the difference between the previous position of the mouse and the current one. For this you need a member like:

public float prevMouseX = 0;

Now, in Update:

float cMouseX = Input.GetAxis( "Mouse X");
float yawChange = prevMouseX - cMouseX;

yaw += yawChange * speedH;
prevMouseX = cMouseX;

Now, the actual position of the mouse is independent of the rotation of the camera. You can now rotate the camera several time around the focal point without regard to the cursor’s actual position (and you should consider storing the position at button 2 down, disabling the cursor, then when button 2 is released restore the cursor position and re-enable it. That is more conventional of the user interface for a rotation of a camera that has nothing to do with actual mouse position.

Now, however, you’ll have a similar observation about motion. If mouse acceleration is still part of this issue, the rotation will still be faster when the mouse is moved at larger distances (as acceleration does), but you’ll observe that this is independent of the actual mouse position, it is related to the distance being moved. To deal with that, assuming you don’t want to fix this by disabling mouse acceleration, is to “unroll” the acceleration you sense by “curving” the mouse input based on distance per time slice. That is, the farther the mouse moves in a particular frame, the less it should apply in increment to yaw. This is a non-linear function, and I’ve used it to good effect in a variety of situations regarding user control input scaling, though never on a mouse in my work.

The basic notion is this formula or a variation of it (imagination prevails here).

// some factors that may well be constants in code
float exp1 = 0.1f;
float exp2 = 0.99f;
float range = 3000f;

// calculation, note yawChange as exampled above

float e1 = Mathf.Pow( yawChange, exp1 );
float e2 = Mathf.Pow( range, exp2 - exp1 ) * yawChange;
float adjustment = e2/e1;
float adjustedYawChange = yawChange - ( adjustment * yawChange );

While this makes little sense at first, the idea is to establish a curve (using exponents, the Pow function) to create a curve that adjusts yawChange, such that the greater the input yawChange the more it is scaled. Some example input/ouputs of yawChange compared to adjustedYawChange with these settings follows:

10, 9.93612
20, 19.76159
100, 94.92586
300, 259.0841
600, 447.2963
1000, 596.9471

Note that an input of 10 produces nearly a 10 output (9.93612), but larger inputs are scaled back, in a curve, so that 1000 returns less than 2/3rds of the input. You can set this up in a spreadsheet, as I did to write this, to see how adjusting exp1, exp2 and range controls the curve. For example, raising the range parameter to 5000 “flattens” the curve a little, so that 1000 produces 744.1905 (closer to the input than when it is 3000). Leaving range at 3000, but lowering exp2 to 0.90 bends the curve so much that it looks like this:

10, 9.87
20, 19.51
200, 161
500, 278
600, 279
900, 221
1000, 171

In this series, the curve is so strong that there’s a peak around 600 input, after which the output actually falls to lower values (eventually becoming negative). This also illustrates that the exp values are a bit touchy to adjust.

The main point here is that a curved interpretation of some kind will allow small motions of the mouse to pass through almost unchanged, but larger swings of the mouse will be reduced, which is the reverse of mouse acceleration.