using UnityEngine; using System.Collections; using UnityEngine.InputSystem; namespace RootMotion { public class CameraController : MonoBehaviour { [System.Serializable] public enum UpdateMode { Update, FixedUpdate, LateUpdate, FixedLateUpdate } public Transform target; // The target Transform to follow //public Transform rotationSpace; // If assigned, will use this Transform's rotation as the rotation space instead of the world space. Useful with spherical planets. public UpdateMode updateMode = UpdateMode.LateUpdate; // When to update the camera? public bool lockCursor = true; // If true, the mouse will be locked to screen center and hidden [Header("Position")] public bool smoothFollow; // If > 0, camera will smoothly interpolate towards the target public Vector3 offset = new Vector3(0, 1.5f, 0.5f); // The offset from target relative to camera rotation public float followSpeed = 10f; // Smooth follow speed [Header("Rotation")] public float rotationSensitivity = 3.5f; // The sensitivity of rotation public float yMinLimit = -20; // Min vertical angle public float yMaxLimit = 80; // Max vertical angle public bool rotateAlways = true; // Always rotate to mouse? [Header("Distance")] public float distance = 10.0f; // The current distance to target public float minDistance = 4; // The minimum distance to target public float maxDistance = 10; // The maximum distance to target public float zoomSpeed = 10f; // The speed of interpolating the distance public float zoomSensitivity = 1f; // The sensitivity of mouse zoom [Header("Blocking")] public LayerMask blockingLayers; public float blockingRadius = 1f; public float blockingSmoothTime = 0.1f; public float blockingOriginOffset; [Range(0f, 1f)] public float blockedOffset = 0.5f; public float x { get; private set; } // The current x rotation of the camera public float y { get; private set; } // The current y rotation of the camera public float distanceTarget { get; private set; } // Get/set distance private Vector3 targetDistance, position; private Quaternion rotation = Quaternion.identity; private Vector3 smoothPosition; private Camera cam; private bool fixedFrame; private float fixedDeltaTime; private Quaternion r = Quaternion.identity; private Vector3 lastUp; private float blockedDistance = 10f, blockedDistanceV; //Rotation public void SetAngles(Quaternion rotation) { Vector3 euler = rotation.eulerAngles; this.x = euler.y; this.y = euler.x; } public void SetAngles(float yaw, float pitch) { this.x = yaw; this.y = pitch; } // Initiate, set the params to the current transformation of the camera relative to the target protected virtual void Awake() { Vector3 angles = transform.eulerAngles; x = angles.y; y = angles.x; distanceTarget = distance; smoothPosition = transform.position; cam = GetComponent(); //_rotate = new Controller(); //_rotate.Player.CameraRotation.performed += context => UpdateInput(); //lastUp = rotationSpace != null ? rotationSpace.up : Vector3.up; } //private void OnEnable() //{ // _rotate.Enable(); //} //private void OnDisable() //{ // _rotate.Disable(); //} protected virtual void Update() { if (updateMode == UpdateMode.Update) UpdateTransform(); } protected virtual void FixedUpdate() { fixedFrame = true; fixedDeltaTime += Time.deltaTime; if (updateMode == UpdateMode.FixedUpdate) UpdateTransform(); } protected virtual void LateUpdate() { UpdateInput(); if (updateMode == UpdateMode.LateUpdate) UpdateTransform(); if (updateMode == UpdateMode.FixedLateUpdate && fixedFrame) { UpdateTransform(fixedDeltaTime); fixedDeltaTime = 0f; fixedFrame = false; } } // Read the user input public void UpdateInput() { if (!cam.enabled) return; // Cursors Cursor.lockState = lockCursor ? CursorLockMode.Locked : CursorLockMode.None; Cursor.visible = lockCursor ? false : true; // Should we rotate the camera? bool rotate = rotateAlways; // delta rotation if (rotate) { // var _pass = _rotate.Player.CameraRotation.ReadValue(); //x += _pass.normalized.x; //y = ClampAngle(y +_pass.normalized.y * rotationSensitivity, yMinLimit, yMaxLimit); } // Distance distanceTarget = Mathf.Clamp(distanceTarget + zoomAdd, minDistance, maxDistance); } // Update the camera transform public void UpdateTransform() { UpdateTransform(Time.deltaTime); } public void UpdateTransform(float deltaTime) { if (!cam.enabled) return; // Rotation //rotation = Quaternion.AngleAxis(x, Vector3.up) * Quaternion.AngleAxis(y, Vector3.right); if (target != null) { // Distance distance += (distanceTarget - distance) * zoomSpeed * deltaTime; // Smooth follow if (!smoothFollow) smoothPosition = target.position; else smoothPosition = Vector3.Lerp(smoothPosition, target.position, deltaTime * followSpeed); // Position Vector3 t = smoothPosition + rotation * offset; Vector3 f = rotation * -Vector3.forward; if (blockingLayers != -1) { RaycastHit hit; if (Physics.SphereCast(t - f * blockingOriginOffset, blockingRadius, f, out hit, blockingOriginOffset + distanceTarget - blockingRadius, blockingLayers)) { blockedDistance = Mathf.SmoothDamp(blockedDistance, hit.distance + blockingRadius * (1f - blockedOffset) - blockingOriginOffset, ref blockedDistanceV, blockingSmoothTime); } else blockedDistance = distanceTarget; distance = Mathf.Min(distance, blockedDistance); } position = t + f * distance; // Translating the camera transform.position = position; } transform.rotation = rotation; } // Zoom input private float zoomAdd { get { float scrollAxis = Input.GetAxis("Mouse ScrollWheel"); if (scrollAxis > 0) return -zoomSensitivity; if (scrollAxis < 0) return zoomSensitivity; return 0; } } // Clamping Euler angles private float ClampAngle(float angle, float min, float max) { if (angle < -360) angle += 360; if (angle > 360) angle -= 360; return Mathf.Clamp(angle, min, max); } } }