using UnityEngine; public class ThirdPersonCamera : MonoBehaviour { public Transform target; public FiremanControl firemanControl; [SerializeField] LayerMask collisionLayers = new LayerMask(); private readonly bool AllowRotation = true; [SerializeField] private Vector2 targetOffset = new Vector2(); [HideInInspector] public bool stayBehindTarget = false; private Transform objectsToRotate; public Vector2 originRotation = new Vector2(); private bool returnToOrigin = true; private float returnSmoothing = 3; public float distance = 5; public float minDistance = 0; public float maxDistance = 10; private Vector2 sensitivity = new Vector2(3, 3); private float zoomSpeed = 1; private float zoomSmoothing = 16; private float zoomAltDelay = 0.5f; private float minAngle = -90; private float maxAngle = 90; private float _zoom_in_timer = 0; private float _zoom_out_timer = 0; [HideInInspector] public float _wanted_distance; private Quaternion _rotation; private Vector2 _input_rotation; private Transform _t; void Start() { _t = transform; _wanted_distance = distance; _input_rotation = originRotation; // If no target set, warn the user if (!target) { Debug.LogWarning("ThirdPersonCamera: No initial target set"); } } void Update() { if (target) { if (firemanControl.driving) { objectsToRotate = firemanControl.carCamPoint.transform; stayBehindTarget = true; } else { objectsToRotate = firemanControl.transform; stayBehindTarget = false; } } } // Camera movement should be done in LateUpdate(), // but it is slightly choppy for some reason so changed to FixedUpdate() // seems to be working fine void FixedUpdate() { if (target) { // Zoom control if (Input.GetAxis("Mouse ScrollWheel") < 0 || _zoom_out_timer > zoomAltDelay) { _wanted_distance += zoomSpeed; } else if (Input.GetAxis("Mouse ScrollWheel") > 0 || _zoom_in_timer > zoomAltDelay) { _wanted_distance -= zoomSpeed; } // Prevent wanted distance from going below or above min and max distance _wanted_distance = Mathf.Clamp(_wanted_distance, minDistance, maxDistance); // If user clicks, change position based on drag direction and sensitivity // Stop at 90 degrees above / below object if (AllowRotation && (Input.GetMouseButton(0) || Input.GetMouseButton(1))) { _input_rotation.x += Input.GetAxis("Mouse X") * sensitivity.x; ClampRotation(); _input_rotation.y -= Input.GetAxis("Mouse Y") * sensitivity.y; _input_rotation.y = Mathf.Clamp(_input_rotation.y, minAngle, maxAngle); _rotation = Quaternion.Euler(_input_rotation.y, _input_rotation.x, 0); // If user is right clicking, set the default position to the current position if (Input.GetMouseButton(1)) { objectsToRotate.rotation = Quaternion.Euler(0, _input_rotation.x, 0); originRotation = _input_rotation; ClampRotation(); } } else { if (stayBehindTarget) { originRotation.x = target.eulerAngles.y; ClampRotation(); } // If Return To Origin, move camera back to the default position if (returnToOrigin) { _input_rotation = Vector3.Lerp(_input_rotation, originRotation, returnSmoothing * Time.deltaTime); } _rotation = Quaternion.Euler(_input_rotation.y, _input_rotation.x, 0); } // Lerp from current distance to wanted distance distance = Mathf.Clamp(Mathf.Lerp(distance, _wanted_distance, Time.deltaTime * zoomSmoothing), minDistance, maxDistance); // Set wanted position based off rotation and distance Vector3 wanted_position = _rotation * new Vector3(targetOffset.x, 0, -_wanted_distance - 0.2f) + target.position + new Vector3(0, targetOffset.y, 0); Vector3 current_position = _rotation * new Vector3(targetOffset.x, 0, 0) + target.position + new Vector3(0, targetOffset.y, 0); RaycastHit hit; if (Physics.Linecast(current_position, wanted_position, out hit, collisionLayers)) { distance = Vector3.Distance(current_position, hit.point) - 0.2f; } // Set the position and rotation of the camera _t.position = _rotation * new Vector3(targetOffset.x, 0.0f, -distance) + target.position + new Vector3(0, targetOffset.y, 0); _t.rotation = _rotation; } } private void ClampRotation() { if (originRotation.x < -180) { originRotation.x += 360; } else if (originRotation.x > 180) { originRotation.x -= 360; } if (_input_rotation.x - originRotation.x < -180) { _input_rotation.x += 360; } else if (_input_rotation.x - originRotation.x > 180) { _input_rotation.x -= 360; } } }