using System.Collections; using System.Collections.Generic; using UnityEngine; [AddComponentMenu("MouseLook ")] public class SmoothMouseLook : MonoBehaviour { [Tooltip("Give the user control over this?")] [SerializeField] bool enable = true; // The speed at which we turn (Mouse Sensitivity) // mouseSensitivity.x is for left <-> right // mouseSensitivity.y is for up <-> down [Tooltip("How fast to turn when moving the mouse (bigger=faster, X: left<->right, Y: up<->down).")] [SerializeField] Vector2 mouseSensitivity = new Vector2(70f, 60f); // How much smoothing goes on for each axis [Tooltip("How smooth/mushy the mouse movement becomes (bigger=smoother, X: left<->right, Y: up<->down).")] [SerializeField] Vector2 smoothing = new Vector2(2f, 2f); [Tooltip("How many frames to wait full control is given to the user.")] [SerializeField] float startupTime = 100.0f; // How far up the head can tilt, measured in angles from the horizon // Must be bigger than headLowerAngleLimit [Tooltip("How many degrees the head can look up at max.")] [SerializeField] float headUpperAngleLimit = 85f; // How far down the head can tilt, measured in angles from the horizon // Must be smaller than headUpperAngleLimit [Tooltip("How many degrees the head can look down at max.")] [SerializeField] float headLowerAngleLimit = -80f; // Invert the Y Axis of the Mouse if true [Tooltip("Invert Mouse Control for up<->down.")] [SerializeField] bool InvertAxisY = true; // Our current rotation from start in degrees float yaw = 0f; float pitch = 0f; // Stores the orientations of the head and body when the game started // We'll derive new orientations by combining these with the variables yaw // and pitch Quaternion bodyStartOrientation; Quaternion headStartOrientation; // A reference to the head object (the object that will rotate up and down) // The body is the current (this) object, so there is no variable needed. // We don't want to expose this to the interface. Instead we just look for a // Child object with type Camera, when the game starts. Transform head; // Two 2D-Vectors that store both axis of the mouse private Vector2 smoothedMouseDelta; // Start is called before the first frame update void Start() { // Find the head – this returns the transform parameter of this objects // first Child of type Camera. If none is found head = null head = GetComponentInChildren<Camera>().transform; // Cache the orientation of body and head. This errors if head was not // found bodyStartOrientation = transform.localRotation; headStartOrientation = head.transform.localRotation; // Lock and hide the cursor Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } // A Easing function that smooths the mouse-movement. This is beeing // done by making the head follow the mouse not exactly, but // with some sort of a lag. The further away the heads point of focus // is compared to the mouse, the faster it will move, once it comes // closer, it slows down – this is called Easing. // // For an intuitive Explaination look here: // https://processing.org/examples/easing.html private Vector2 EaseMouseDelta(Vector2 mouseDelta) { // Scale input against the sensitivity setting and multiply that // with the smoothing value. mouseDelta *= mouseSensitivity.x * smoothing.x * Time.deltaTime; mouseDelta *= mouseSensitivity.y * smoothing.y * Time.deltaTime; // Linear Interpolation ("Lerp") between the smoothed Delta from // the last round/Frame and the actual mouse Position. smoothedMouseDelta.x = Mathf.Lerp(smoothedMouseDelta.x, mouseDelta.x, 1f / smoothing.x); smoothedMouseDelta.y = Mathf.Lerp(smoothedMouseDelta.y, mouseDelta.y, 1f / smoothing.y); // Return the smoothed 2D-Vector return smoothedMouseDelta; } // Every time Physics updates, update the movemnent of this object. // Do this in FixedUpdate to keep pace with physically simulated Objects void FixedUpdate() { // Read the Position-Change between this Frame and the last // Note: GetRawAxis gives more sensitivity var mouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")); // Run the Smoothing-Function we defined above on the Mouse // Vector we read before and return a smoothed one smoothedMouseDelta = EaseMouseDelta(mouseDelta); // Flip the vertical Control, if InvertAxisY is true if (InvertAxisY) { smoothedMouseDelta.y *= -1; } if (enable) { // Add the mouse movements to the current value of yaw and pitch yaw += smoothedMouseDelta.x; pitch += smoothedMouseDelta.y; // Scale the values initially to avoid jumps on scene startup yaw = SoftStart(yaw); pitch = SoftStart(pitch); // Clamp pitch so that we can't look directly down or up pitch = Mathf.Clamp(pitch, headLowerAngleLimit, headUpperAngleLimit); } else { yaw = 0.0f; pitch = 0.0f; } // Compute rotations by rotating around a fixed axis (rotate yaw-degrees // around the up direction for the body, and pitch degrees around the // right direction for the head). // Note: 90 deg need to be added, to get the initial orientation right var bodyRotation = Quaternion.AngleAxis(yaw, Vector3.up); var headRotation = Quaternion.AngleAxis(pitch, Vector3.left); // Debug.LogFormat("bodyRotation: {0}, headRotation: {1}", bodyRotation, headRotation); // Finally combine the rotations for body and head with the start rotations transform.localRotation = bodyRotation * bodyStartOrientation; head.transform.localRotation = headRotation * headStartOrientation; } float SoftStart(float invalue) { if (Time.frameCount < startupTime) { return invalue * Mathf.Lerp(0.0f, 1.0f, Time.frameCount/startupTime); } else { return invalue; } } }