- Home /
Mouse rotation with limits: limit overrun protection works on positive overruns only?
So I am trying to get a system working whereby selecting a unit in game creates 'handles' for maneuvering it in 3 dimensions in a turn-based setting. An example would be the yaw handle; when a unit is clicked the default maneuver handle is yaw, to allow it to turn. There is a limited range of yaw available, likewise for the other two degrees of rotational freedom.
In my test case there are 90 degrees of yaw available. Therefor you should be able to drag on the handle and rotate the unit 45 degrees to either side.
There are plenty of Unity Answers topics on rotation via mouse drag, but very few on rotation via mouse drag within limits. As long as I stayed safely between my limits, the rotation worked fine. But if I moved the mouse quickly while approaching the limits of the yaw available to me, there would be an overrun. Similar overruns are described in this topic within the selected answer.
So I thought to myself how I might solve this. I came up with a few approaches - I've been banging up against this problem for a week and getting mighty frustrated. Eventually I got to this:
void Start () {
permitted = degrees / 2;
currentRotation = new Vector3(0, 0, 0);
}
void Update () {
if (mouseMoving) {
currentMouse = (Input.mousePosition - mouseStart);
currentRotation.y = -(currentMouse.x + currentMouse.y) * Time.deltaTime * 20;
float oldAngle = angle;
angle += currentRotation.y;
if (-permitted > angle) {
currentRotation.y = -permitted - oldAngle;
}
if (angle > permitted) {
currentRotation.y = permitted - oldAngle;
}
angle = Mathf.Clamp (angle, -permitted, permitted);
target.transform.Rotate (currentRotation);
mouseStart = Input.mousePosition;
}
}
void OnMouseDown() {
mouseMoving = true;
mouseStart = Input.mousePosition;
}
void OnMouseUp () {
mouseMoving = false;
}
Permitted is a float that determines the degrees to either side that can be traveled. Start is used instead of awake to allow time for the unit that spawns the handles to set the degrees as appropriate for that unit type. Boolean "mouseMoving" is turned on by clicking upon the handle collider, turned off by OnMouseUp.
The problem is that while the positive overrun protections works fine as you can never turn further than 45 degrees, the negative overrun protection won't work! It gets stuck at about -44.751 - that's the furthest I can push it. And if it's off by such a minute amount, it means that the whole implementation of the negative limit is wrong. Any error there indicates I've made a mistake that I can't see.
I don't understand what I have gotten wrong in the math. The working section is as follows:
if (angle > permitted) {
currentRotation.y = permitted - oldAngle;
}
The inverse should be:
if (-permitted > angle) {
currentRotation.y = -permitted - oldAngle;
}
But it doesn't work! My conceptualization of this is that if the limit of -45 in this case is exceeded by a number further down the negatives, instead of allowing the mouse input to be used, it takes the previously recorded position and subtracts that from the lower limit. So if you input -50, it rejects it and reverts to where you were the previous update - say -44, and since the limit is -45, you'd subtract -44 from -45, yielding -1. That -1 would then be applied as rotation.
It works for the positive limit when all of the above numbers are their positive counterparts but not for the negative limit. I can't figure out for the life of me what specific error I have made and really would appreciate some fresh eyes to see what I've done wrong here.