Skip to content

Instantly share code, notes, and snippets.

@JackDraak
Created November 20, 2018 10:16
Show Gist options
  • Save JackDraak/50438ea461dc5a85be8b02fc7c3c1a9a to your computer and use it in GitHub Desktop.
Save JackDraak/50438ea461dc5a85be8b02fc7c3c1a9a to your computer and use it in GitHub Desktop.
Mouse gimbal controller for Unity.
using UnityEngine;
public class MouseGimbal : MonoBehaviour
{
[SerializeField] [Range(0,89)] float maxRotationDegrees = 10.0f; // At 90+ gimbal oddities must be dealt with.
[SerializeField] bool ClampToMaxRotationDegrees = true; // Disable for free rotation.
[SerializeField] float rotationSpeed = 10.0f;
const float fullArc = 360.0f;
const float halfArc = 180.0f;
const float nullArc = 0.0f;
void Update () { Tilt(); }
void Tilt()
{
// Apply the 'pre-clamp' rotation (rotation-Z and rotation-X from X & Y of mouse, respectively).
if (maxRotationDegrees > 0) { SimpleRotation(GetMouseInput()); }
// Clamp rotation to maxRotationDegrees.
if (ClampToMaxRotationDegrees) { ClampRotation(transform.rotation.eulerAngles); }
}
void ClampRotation(Vector3 tempEulers)
{
tempEulers.x = ClampPlane(tempEulers.x);
tempEulers.z = ClampPlane(tempEulers.z);
tempEulers.y = nullArc; // ClampPlane(tempEulers.y); // *See GIST note below...
transform.rotation = Quaternion.Euler(tempEulers);
///Debug.Log(tempEulers);
}
float ClampPlane(float plane)
{
if (OkayLow(plane) || OkayHigh(plane)) DoNothing(); // Plane 'in range'.
else if (BadLow(plane)) plane = Mathf.Clamp(plane, nullArc, maxRotationDegrees);
else if (BadHigh(plane)) plane = Mathf.Clamp(plane, fullArc - maxRotationDegrees, fullArc);
else Debug.LogWarning("WARN: invalid plane condition");
return plane;
}
Vector2 GetMouseInput()
{
Vector2 mouseXY;
mouseXY.x = -Input.GetAxis("Mouse X"); // MouseX -> rotZ.
mouseXY.y = Input.GetAxis("Mouse Y"); // MouseY -> rotX.
return mouseXY;
}
void SimpleRotation(Vector2 mouseXY)
{
Vector3 rotation = Vector3.zero;
rotation.x = mouseXY.y * Time.deltaTime * rotationSpeed;
rotation.z = mouseXY.x * Time.deltaTime * rotationSpeed;
transform.Rotate(rotation, Space.Self);
}
void DoNothing() { }
bool OkayHigh(float test) { return (test >= fullArc - maxRotationDegrees && test <= fullArc); }
bool OkayLow(float test) { return (test >= nullArc && test <= maxRotationDegrees); }
bool BadHigh(float test) { return (test > halfArc && !OkayHigh(test)); }
bool BadLow(float test) { return (test < halfArc && !OkayLow(test)); }
}
@JackDraak
Copy link
Author

Notes on the Y-plane: You can clamp it to zero, or you can clamp it the same as X & Z, or, you could extend the code and clamp it in it's own unique way.

*If you toggle the bool: ClampToMaxRotationDegrees to false, none of the planes will clamp.

Notes on angle values: If you watch the object in the inspector, you'll see the angles clamping to +/- 10 (or whatever angle you've set in the inspector). But wait, you say, we're clamping them to 0 thru 10 or 350 thru 360 only! Both things are true, and that's probably why you were getting unexpected results using a 'minRotation' of negative 10.

*If you set the Rotate() on line 55 to Space.World, your results will be fairly un-predictable, in proportion to the maxRotationDegrees you are using.

@JackDraak
Copy link
Author

JackDraak commented Nov 20, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment